Now that all the data is loaded in for each position, including
fantasy point values, I can officially dig in to determine which stats
or areas are most predictive in determining fantasy football access. The
answer may vary by position but I plan on digging in deeply, making a
bunch of different visualizations to find some sort of consensus that
can be used for drafting teams next season. After creating data sets,
joining them by position and the code for targets working now somehow, I
feel as if I addressed a majority of the issues I had previously been
facing. I look forward to digging in further.
library(tidyverse)
library(nflreadr)
library(tidyverse)
library(ggalt)
library(ggbeeswarm)
library(ggrepel)
NFL<- load_pbp(
seasons = most_recent_season(),
file_type = getOption("nflreadr.prefer", default = "rds")
)
NFLRosters<- load_rosters(
seasons = most_recent_season(roster = TRUE),
file_type = getOption("nflreadr.prefer", default = "rds")
)
NFL <- NFL %>% mutate(across(where(is.numeric), ~ replace_na(., 0)))
WR_55 <- read_csv("~/code/mcharles317.github.io/WR55.csv")
Rows: 55 Columns: 5── Column specification ──────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): PLAYER, fantasy_player_id
dbl (3): RANK, FPTS, FPTS/G
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
RB_55 <- read_csv("~/code/mcharles317.github.io/RB55.csv")
New names:Rows: 55 Columns: 15── Column specification ──────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): PLAYER, fantasy_player_id
dbl (13): RANK, LG, 20+, TD...6, REC, TGT, YDS, Y/R, TD...11, FL, G, FPTS, FPTS/G
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
TE_24 <- read_csv("~/code/mcharles317.github.io/TE24.csv")
Rows: 24 Columns: 9── Column specification ──────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): PLAYER, fantasy_player_id
dbl (7): RANK, Y/R, LG, 20+, TD, FPTS, FPTS/G
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
QB24 <- read_csv("~/code/mcharles317.github.io/QB24.csv")
Rows: 24 Columns: 19── Column specification ──────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): PLAYER, fantasy_player_id, ROST
dbl (15): RANK, CMP, ATT, PCT, Y/A, TD, INT, SACKS, R_ATT, R_YDS, R_TD, FL, G, FPTS, FPTS/G
num (1): YDS
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
TE <- NFL %>%
filter(fantasy_player_name == "D.Goedert" | fantasy_player_name == "D.Schultz" )
MyTEs <- NFL %>%
filter(fantasy_player_id == "00-0034351" | fantasy_player_id == "00-0034383" ) %>%
group_by(fantasy_player_id, fantasy_player_name) %>%
summarise(TotalReceivingYds = sum(receiving_yards), Avg_ReceivingYds = mean(receiving_yards), Total_AirYards= sum(air_yards), Avg_AirYards= mean(air_yards), Avg__YAC = mean (yards_after_catch), Total_YAC = sum (yards_after_catch), Avg_AirEPA = mean (air_epa), Total_AirEPA = sum(air_epa), Avg_YACEPA =mean (yac_epa), Total_YacEPA = sum(yac_epa), Avg_comp_air_epa = mean(comp_air_epa), Total_comp_air_epa = sum (comp_air_epa), Total_YAC_Comp = sum(comp_yac_epa), Avg_YAC_Comp = mean(comp_yac_epa), Total_YAC_WPA = sum(yac_wpa), Avg_YAC_WPA = mean(yac_wpa))
`summarise()` has grouped output by 'fantasy_player_id'. You can override using the `.groups` argument.
MyQB <- NFL %>%
filter(passer_player_id == "00-0036442")%>%
group_by(passer_player_id, name)%>%
summarise(Avg_comp_air_epa = mean(comp_air_epa), Total_comp_air_epa = sum (comp_air_epa), Total_pass_touchdown = sum (pass_touchdown), Total_complete_pass = sum(complete_pass), Total_Pass_attempt = sum(pass_attempt), Interceptions = sum(interception), TotalQBEPA =sum(qb_epa), Avg_QBEPA = mean(qb_epa), Avg_pass_oe = mean(pass_oe), Avg_comp_air_epa = mean(comp_air_epa), Total_comp_air_epa = sum(comp_air_epa), TotalDropbacks= sum (qb_dropback))
`summarise()` has grouped output by 'passer_player_id'. You can override using the `.groups` argument.
QB_by_Week<- NFL%>%
filter(passer_player_id == "00-0036442")%>%
group_by(passer_player_id, week, name)%>%
summarise(Avg_comp_air_epa = mean(comp_air_epa), Total_comp_air_epa = sum (comp_air_epa), Total_pass_touchdown = sum (pass_touchdown), Total_complete_pass = sum(complete_pass), Total_Pass_attempt = sum(pass_attempt), TotalQBEPA =sum(qb_epa), Avg_QBEPA = mean(qb_epa), Avg_pass_oe = mean(pass_oe), Avg_comp_air_epa = mean(comp_air_epa), Total_comp_air_epa = sum(comp_air_epa), TotalDropbacks= sum (qb_dropback), Interceptions = sum(interception), GamesPlayed = n_distinct(game_id))
`summarise()` has grouped output by 'passer_player_id', 'week'. You can override using the `.groups` argument.
QB_Rushing <- NFL %>%
filter(fantasy_id == "00-0036442") %>%
filter(rush_attempt == 1) %>%
mutate(rushing_yards = replace_na(rushing_yards, 0)) %>%
group_by(fantasy_id, name) %>%
summarise(TotalRushAttempts = sum(rush_attempt), TotalRushYards = sum(rushing_yards), GamesPlayed = n_distinct(game_id))
`summarise()` has grouped output by 'fantasy_id'. You can override using the `.groups` argument.
QBOverall <- MyQB %>%
inner_join(QB_Rushing, by= "name")
QB_Rushing_Weekly<- NFL %>%
filter(rusher == "J.Burrow") %>%
group_by(rusher, name, week) %>%
summarise(TotalRushAttempts = sum(rush_attempt), TotalRushYards = sum(rushing_yards))
`summarise()` has grouped output by 'rusher', 'name'. You can override using the `.groups` argument.
QB_Overall_Weekly <- QB_by_Week %>%
inner_join(QB_Rushing_Weekly, by= "name")
MyWR <- NFL %>%
filter(fantasy_player_id == "00-0030564" | fantasy_player_id == "00-0036410" | fantasy_player_id == "00-0037239" | fantasy_player_id == "00-0033536" | fantasy_player_id == "00-0037247" | fantasy_player_id == "00-0036988") %>%
group_by(fantasy_player_id, fantasy_player_name) %>%
summarise (Total_AirYards= sum(air_yards), Avg_AirYards= mean(air_yards), Avg__YAC = mean (yards_after_catch), Total_YAC = sum (yards_after_catch), Avg_AirEPA = mean (air_epa), Total_AirEPA = sum(air_epa), Avg_YACEPA =mean (yac_epa), Total_YacEPA = sum(yac_epa), Avg_comp_air_epa = mean(comp_air_epa), Total_comp_air_epa = sum (comp_air_epa), Total_YAC_Comp = sum(comp_yac_epa), Avg_YAC_Comp = mean(comp_yac_epa), Total_YAC_WPA = sum(yac_wpa), Avg_YAC_WPA = mean(yac_wpa),TotalReceivingYds = sum(receiving_yards), Avg_ReceivingYds = mean(receiving_yards), TotalEPA = sum(epa), TotalExpectedYAC_EPA = sum (xyac_epa),AvgExpectedYAC_EPA = mean (xyac_epa), GamesPlayed = n_distinct(game_id))
`summarise()` has grouped output by 'fantasy_player_id'. You can override using the `.groups` argument.
WR_Weekly <- NFL %>%
filter(fantasy_player_id == "00-0030564" | fantasy_player_id == "00-0036410" | fantasy_player_id == "00-0037239" | fantasy_player_id == "00-0033536" | fantasy_player_id == "00-0037247" | fantasy_player_id == "00-0036988") %>%
group_by(fantasy_player_id, fantasy_player_name, week) %>%
summarise (Total_AirYards= sum(air_yards), Avg_AirYards= mean(air_yards), Avg__YAC = mean (yards_after_catch), Total_YAC = sum (yards_after_catch), Avg_AirEPA = mean (air_epa), Total_AirEPA = sum(air_epa), Avg_YACEPA =mean (yac_epa), Total_YacEPA = sum(yac_epa), Avg_comp_air_epa = mean(comp_air_epa), Total_comp_air_epa = sum (comp_air_epa), Total_YAC_Comp = sum(comp_yac_epa), Avg_YAC_Comp = mean(comp_yac_epa), Total_YAC_WPA = sum(yac_wpa), Avg_YAC_WPA = mean(yac_wpa), TotalEPA = sum(epa), TotalExpectedYAC_EPA = sum (xyac_epa),AvgExpectedYAC_EPA = mean (xyac_epa), TotalYardsGained = sum(yards_gained), GamesPlayed = n_distinct(game_id))
`summarise()` has grouped output by 'fantasy_player_id', 'fantasy_player_name'. You can override using the `.groups` argument.
WR_ThroughWeek4 <- NFL %>%
filter(fantasy_player_id == "00-0033921" | fantasy_player_id == "00-0034764" | fantasy_player_id == "00-0036913" | fantasy_player_id == "00-0036963" | fantasy_player_id == "00-0036252", week <= 4) %>%
group_by(fantasy_player_id, fantasy_player_name) %>%
summarise (Total_AirYards= sum(air_yards), Avg_AirYards= mean(air_yards), Avg__YAC = mean (yards_after_catch), Total_YAC = sum (yards_after_catch), Avg_AirEPA = mean (air_epa), Total_AirEPA = sum(air_epa), Avg_YACEPA =mean (yac_epa), Total_YacEPA = sum(yac_epa), Avg_comp_air_epa = mean(comp_air_epa), Total_comp_air_epa = sum (comp_air_epa), Total_YAC_Comp = sum(comp_yac_epa), Avg_YAC_Comp = mean(comp_yac_epa), Total_YAC_WPA = sum(yac_wpa), Avg_YAC_WPA = mean(yac_wpa), TotalEPA = sum(epa), TotalExpectedYAC_EPA = sum (xyac_epa),AvgExpectedYAC_EPA = mean (xyac_epa), TotalYardsGained = sum(yards_gained), GamesPlayed = n_distinct(game_id))
`summarise()` has grouped output by 'fantasy_player_id'. You can override using the `.groups` argument.
MyRB_receiving<- NFL %>%
filter(fantasy_player_id == "00-0036223" | fantasy_player_id == "00-0035700" | fantasy_player_id == "00-0036924" | fantasy_player_id == "00-0036275")%>%
group_by(fantasy_player_id, fantasy_player_name) %>%
summarise(TotalReceivingYds = sum(receiving_yards), Avg_ReceivingYds = mean(receiving_yards), Total_AirYards= sum(air_yards), Avg_AirYards= mean(air_yards), Avg__YAC = mean (yards_after_catch), Total_YAC = sum (yards_after_catch), Avg_AirEPA = mean (air_epa), Total_AirEPA = sum(air_epa), Avg_YACEPA =mean (yac_epa), Total_YacEPA = sum(yac_epa), Avg_comp_air_epa = mean(comp_air_epa), Total_comp_air_epa = sum (comp_air_epa), Total_YAC_Comp = sum(comp_yac_epa), Avg_YAC_Comp = mean(comp_yac_epa), Total_YAC_WPA = sum(yac_wpa), Avg_YAC_WPA = mean(yac_wpa), TotalEPA = sum(epa), TotalExpectedYAC_EPA = sum (xyac_epa),AvgExpectedYAC_EPA = mean (xyac_epa), TotalYardsGained = sum(yards_gained), GamesPlayed = n_distinct(game_id))
`summarise()` has grouped output by 'fantasy_player_id'. You can override using the `.groups` argument.
MyRB<- NFL %>%
filter(fantasy_player_id == "00-0036223" | fantasy_player_id == "00-0035700" | fantasy_player_id == "00-0036924" | fantasy_player_id == "00-0036275")%>%
filter(rush_attempt == 1) %>%
mutate(rushing_yards = replace_na(rushing_yards, 0)) %>%
group_by(fantasy_player_id, fantasy_player_name) %>%
summarise(TotalRushAttempts = sum(rush_attempt), TotalRushYards = sum(rushing_yards), YPC = TotalRushYards/TotalRushAttempts, GamesPlayed = n_distinct(game_id))
`summarise()` has grouped output by 'fantasy_player_id'. You can override using the `.groups` argument.
MY_RB_Overall <- MyRB%>%
inner_join(MyRB_receiving, by= "fantasy_player_name")
#Question:
EveryWR<- NFLRosters %>%
filter(position == "WR")
EveryRB<- NFLRosters %>%
filter(position == "RB")
All_RB <- EveryRB %>%
inner_join(NFL, by=c("gsis_id" = "fantasy_player_id"))
All_RB <- All_RB %>%
group_by(full_name, fantasy_data_id,position,gsis_id) %>%
summarise(TotalRushAttempts = sum(rush_attempt), TotalRushYards = sum(rushing_yards), YPC = TotalRushYards/TotalRushAttempts)
`summarise()` has grouped output by 'full_name', 'fantasy_data_id', 'position'. You can override using the `.groups` argument.
EveryRBReceiving<- NFLRosters %>%
filter(position == "RB")
All_RB_Receiving<- EveryRBReceiving %>%
inner_join(NFL, by=c("gsis_id" = "fantasy_player_id"))
EveryRBReceiving <-All_RB_Receiving %>%
group_by(full_name, fantasy_data_id,position) %>%
summarise(TotalReceivingYds = sum(receiving_yards), Avg_ReceivingYds = mean(receiving_yards), Total_AirYards= sum(air_yards), Avg_AirYards= mean(air_yards), Avg__YAC = mean (yards_after_catch), Total_YAC = sum (yards_after_catch), Avg_AirEPA = mean (air_epa), Total_AirEPA = sum(air_epa), Avg_YACEPA =mean (yac_epa), Total_YacEPA = sum(yac_epa), Avg_comp_air_epa = mean(comp_air_epa), Total_comp_air_epa = sum (comp_air_epa), Total_YAC_Comp = sum(comp_yac_epa), Avg_YAC_Comp = mean(comp_yac_epa), Total_YAC_WPA = sum(yac_wpa), Avg_YAC_WPA = mean(yac_wpa), TotalEPA = sum(epa), TotalYardsGained = sum(yards_gained), GamesPlayed = n_distinct(game_id))
`summarise()` has grouped output by 'full_name', 'fantasy_data_id'. You can override using the `.groups` argument.
EveryTE<- NFLRosters %>%
filter(position == "TE")
All_TE <- EveryTE %>%
inner_join(NFL, by=c("gsis_id" = "fantasy_player_id"))
EveryQB<- NFLRosters %>%
filter(position == "QB")
All_QB <- EveryQB %>%
inner_join(NFL, by=c("gsis_id" = "fantasy_player_id"))
All_QB <- All_QB %>%
group_by(full_name, gsis_id,position) %>%
summarise (Avg_comp_air_epa = mean(comp_air_epa), Total_comp_air_epa = sum (comp_air_epa), Total_pass_touchdown = sum (pass_touchdown), Total_complete_pass = sum(complete_pass), Total_Pass_attempt = sum(pass_attempt), Interceptions = sum(interception), TotalQBEPA =sum(qb_epa), Avg_QBEPA = mean(qb_epa), Avg_pass_oe = mean(pass_oe), Avg_comp_air_epa = mean(comp_air_epa), Total_comp_air_epa = sum(comp_air_epa), TotalDropbacks= sum (qb_dropback))
`summarise()` has grouped output by 'full_name', 'gsis_id'. You can override using the `.groups` argument.
All_WR <- EveryWR %>%
inner_join(NFL, by=c("gsis_id" = "fantasy_player_id"))
All_WR <- All_WR %>%
group_by(full_name, fantasy_id,position) %>%
rename(fantasy_player_id = fantasy_id) %>%
summarise(Total_AirYards= sum(air_yards), Avg_AirYards= mean(air_yards), Avg__YAC = mean (yards_after_catch), Total_YAC = sum (yards_after_catch), Avg_AirEPA = mean (air_epa), Total_AirEPA = sum(air_epa), Avg_YACEPA =mean (yac_epa), Total_YacEPA = sum(yac_epa), Avg_comp_air_epa = mean(comp_air_epa), Total_comp_air_epa = sum (comp_air_epa), Total_YAC_Comp = sum(comp_yac_epa), Avg_YAC_Comp = mean(comp_yac_epa), Total_YAC_WPA = sum(yac_wpa), Avg_YAC_WPA = mean(yac_wpa),TotalReceivingYds = sum(receiving_yards), Avg_ReceivingYds = mean(receiving_yards), TotalEPA = sum(epa), TotalExpectedYAC_EPA = sum (xyac_epa),AvgExpectedYAC_EPA = mean (xyac_epa), TotalYardsGained = sum(yards_gained))
`summarise()` has grouped output by 'full_name', 'fantasy_player_id'. You can override using the `.groups` argument.
All_WR <-All_WR %>%
filter(full_name != "Josh Ali")
ggplot() + geom_point(data=All_WR, aes(x=Avg_AirEPA, y=Avg_YAC_Comp))

ggplot() +
geom_point(data=All_WR, aes(x=Avg_AirEPA, y=Avg_comp_air_epa)) +
geom_smooth(data=All_WR, aes(x=Avg_AirEPA, y=Avg_comp_air_epa), method="lm") +
geom_point(data=MyWR, aes(x=Avg_AirEPA, y=Avg_comp_air_epa), color="red") +
geom_text_repel(
data=MyWR,
aes(x=Avg_AirEPA, y=Avg_comp_air_epa, label=fantasy_player_name))

ggplot() +
geom_point(data=All_WR, aes(x=Total_AirYards, y=TotalReceivingYds)) +
geom_smooth(data=All_WR, aes(x=Total_AirYards, y=TotalReceivingYds), method="lm") +
geom_point(data=MyWR, aes(x=Total_AirYards, y=TotalReceivingYds), color="red") +
geom_text_repel(
data=MyWR,
aes(x=Total_AirYards, y=TotalReceivingYds, label=fantasy_player_name))

ggplot() +
geom_point(data=All_WR, aes(x=Avg_AirYards, y=Avg_ReceivingYds)) +
geom_smooth(data=All_WR, aes(x=Avg_AirYards, y=Avg_ReceivingYds), method="lm") +
geom_point(data=MyWR, aes(x=Avg_AirYards, y=Avg_ReceivingYds), color="red")

ggplot() +
geom_point(data=All_RB, aes(x=YPC, y=TotalRushAttempts)) +
geom_smooth(data=All_RB, aes(x=YPC, y=TotalRushAttempts), method="lm") +
geom_point(data=MyRB, aes(x=YPC, y=TotalRushAttempts), color="red")

ggplot() +
geom_point(data=EveryRBReceiving, aes(x=Avg_AirEPA, y=Avg_YAC_Comp)) +
geom_smooth(data=EveryRBReceiving, aes(x=Avg_AirEPA, y=Avg_YAC_Comp), method="lm") +
geom_point(data=MyRB_receiving, aes(x=Avg_AirEPA, y=Avg_YAC_Comp), color="red")

ggplot() +
geom_point(data=All_WR, aes(x=Total_AirEPA, y=TotalEPA)) +
geom_smooth(data=All_WR, aes(x=Total_AirEPA, y=TotalEPA), method="lm") +
geom_point(data=MyWR, aes(x=Total_AirEPA, y=TotalEPA), color="red")

AJ <- All_WR %>%
filter(full_name == "A.J. Brown")
Chase <- All_WR %>%
filter(full_name == "Ja'Marr Chase")
Ja’Marr Chase
ggplot() +
geom_point(data=All_WR, aes(x=Avg_AirYards, y=Avg_ReceivingYds)) +
geom_smooth(data=All_WR, aes(x=Avg_AirYards, y=Avg_ReceivingYds), method="lm") +
geom_point(data=AJ, aes(x=Avg_AirYards, y=Avg_ReceivingYds), color="red")

ggplot() +
geom_point(data=All_WR, aes(x=Avg_AirYards, y=Avg_ReceivingYds)) +
geom_smooth(data=All_WR, aes(x=Avg_AirYards, y=Avg_ReceivingYds), method="lm") +
geom_point(data=Chase, aes(x=Avg_AirYards, y=Avg_ReceivingYds), color="red")

Justin Jefferson
Jetts <- All_WR %>%
filter(full_name == "Justin Jefferson")
ggplot() +
geom_point(data=All_WR, aes(x=Avg_AirYards, y=Avg_ReceivingYds)) +
geom_smooth(data=All_WR, aes(x=Avg_AirYards, y=Avg_ReceivingYds), method="lm") +
geom_point(data=Jetts, aes(x=Avg_AirYards, y=Avg_ReceivingYds), color="red")

Gabe <- All_WR %>%
filter(full_name == "Gabe Davis")
Gabe Davis
ggplot() +
geom_point(data=All_WR, aes(x=Avg_AirYards, y=Avg_ReceivingYds)) +
geom_smooth(data=All_WR, aes(x=Avg_AirYards, y=Avg_ReceivingYds), method="lm") +
geom_point(data=Gabe, aes(x=Avg_AirYards, y=Avg_ReceivingYds), color="red")

ggplot() +
geom_point(data=All_WR, aes(x=Avg_YACEPA, y=Avg_AirEPA)) +
geom_smooth(data=All_WR, aes(x=Avg_YACEPA, y=Avg_AirEPA), method="lm") +
geom_point(data=Chase, aes(x=Avg_YACEPA, y=Avg_AirEPA), color="red")

Jeudy <- All_WR %>%
filter(full_name == "Jerry Jeudy")
WREPA<- All_WR %>%
group_by(full_name) %>%
summarise(TotalEPA, Total_AirEPA, TotalExpectedYAC_EPA, AvgExpectedYAC_EPA, TotalReceivingYds)
`summarise()` has grouped output by 'full_name'. You can override using the `.groups` argument.
View(WR_Targets)
My_WR_Targets <- NFL %>%
filter(!is.na(receiver_player_name), full_name != "Emeka Emezie") %>%
group_by(receiver_player_id, receiver_player_name, complete_pass) %>%
summarise(count = n()) %>%
pivot_wider(names_from = complete_pass, values_from = count) %>%
rename(receptions = `1`, incompletions = `0`) %>%
mutate(receptions = replace_na(receptions, 0), incompletions = replace_na(incompletions, 0)) %>%
mutate(targets = receptions + incompletions) %>%
inner_join(MyWR, by=c("receiver_player_id"="fantasy_player_id"))
Error in `filter()`:
! Problem while computing `..2 = full_name != "Emeka Emezie"`.
Caused by error in `mask$eval_all_filter()`:
! object 'full_name' not found
Backtrace:
1. ... %>% ...
10. dplyr:::filter.data.frame(., !is.na(receiver_player_name), full_name != "Emeka Emezie")
11. dplyr:::filter_rows(.data, ..., caller_env = caller_env())
12. dplyr:::filter_eval(dots, mask = mask, error_call = error_call)
14. mask$eval_all_filter(dots, env_filter)
My_WR_Targets_PG <- My_WR_Targets %>%
summarise( TargetsPegGame = targets/GamesPlayed)
`summarise()` has grouped output by 'receiver_player_id'. You can override using the `.groups` argument.
WR_Targets <- NFL %>%
filter(!is.na(receiver_player_name), full_name != "Emeka Emezie") %>%
group_by(receiver_player_id, receiver_player_name, complete_pass) %>%
summarise(count = n(), GamesPlayed = n_distinct(game_id)) %>%
pivot_wider(names_from = complete_pass, values_from = count) %>%
rename(receptions = `1`, incompletions = `0`) %>%
mutate(receptions = replace_na(receptions, 0), incompletions = replace_na(incompletions, 0)) %>%
mutate(targets = receptions + incompletions) %>%
inner_join(All_WR, by=c("receiver_player_id"="fantasy_player_id"))
Error in `filter()`:
! Problem while computing `..2 = full_name != "Emeka Emezie"`.
Caused by error in `mask$eval_all_filter()`:
! object 'full_name' not found
Backtrace:
1. ... %>% ...
10. dplyr:::filter.data.frame(., !is.na(receiver_player_name), full_name != "Emeka Emezie")
11. dplyr:::filter_rows(.data, ..., caller_env = caller_env())
12. dplyr:::filter_eval(dots, mask = mask, error_call = error_call)
14. mask$eval_all_filter(dots, env_filter)
WR_Targets_PG <- WR_Targets %>%
summarise( TargetsPegGame = targets/GamesPlayed)
`summarise()` has grouped output by 'receiver_player_id', 'receiver_player_name'. You can override using the `.groups` argument.
ggplot() +
geom_point(data=WR_Targets, aes(x=targets, y=TotalEPA)) +
geom_smooth(data=WR_Targets, aes(x=targets, y=TotalEPA), method="lm") +
geom_point(data=My_WR_Targets, aes(x=targets, y=TotalEPA), color="red") +
geom_text_repel(
data=My_WR_Targets,
aes(x=targets, y=TotalEPA, label=fantasy_player_name))

All_TE <- All_TE %>%
group_by(full_name, fantasy_data_id,position) %>%
summarise(Total_AirYards= sum(air_yards), Avg_AirYards= mean(air_yards), Avg__YAC = mean (yards_after_catch), Total_YAC = sum (yards_after_catch), Avg_AirEPA = mean (air_epa), Total_AirEPA = sum(air_epa), Avg_YACEPA =mean (yac_epa), Total_YacEPA = sum(yac_epa), Avg_comp_air_epa = mean(comp_air_epa), Total_comp_air_epa = sum (comp_air_epa), Total_YAC_Comp = sum(comp_yac_epa), Avg_YAC_Comp = mean(comp_yac_epa), Total_YAC_WPA = sum(yac_wpa), Avg_YAC_WPA = mean(yac_wpa),TotalReceivingYds = sum(receiving_yards), Avg_ReceivingYds = mean(receiving_yards))
`summarise()` has grouped output by 'full_name', 'fantasy_data_id'. You can override using the `.groups` argument.
RB_Rushes<- NFL %>%
filter(!is.na(rusher_player_name)) %>%
group_by(rusher_player_id, rusher_player_name) %>%
summarise(count = n())
`summarise()` has grouped output by 'rusher_player_id'. You can override using the `.groups` argument.
ALL_WR_FP <- All_WR %>%
inner_join(WR_55, by=c("fantasy_player_id"))
ALL_WR_FP <- ALL_WR_FP %>%
filter(full_name != "Emeka Emezie")
ALL_RB_FP <- All_RB %>%
inner_join(RB_55, by=c("gsis_id"="fantasy_player_id"))
ALL_QB_FP <- All_QB %>%
inner_join(QB24, by=c("gsis_id"="fantasy_player_id"))
ALL_TE_FP <- EveryTE %>%
inner_join(TE_24, by=c("gsis_id"="fantasy_player_id"))
ALL_WR_FP10 <- All_WR %>%
inner_join(WR_55, by=c("fantasy_player_id")) %>%
filter(full_name != "Emeka Emezie") %>%
arrange(desc(`FPTS/G`)) %>%
head(10)
ALL_RB_FP10<- All_RB %>%
inner_join(RB_55, by=c("gsis_id"="fantasy_player_id")) %>%
arrange(desc(`FPTS/G`)) %>%
head(10)
ALL_QB_FP10 <- All_QB %>%
inner_join(QB24, by=c("gsis_id"="fantasy_player_id")) %>%
arrange(desc(`FPTS/G`)) %>%
head(10)
ALL_TE_FP10 <- EveryTE %>%
inner_join(TE_24, by=c("gsis_id"="fantasy_player_id")) %>%
arrange(desc(`FPTS/G`)) %>%
head(10)
#Quaretback Analysis My initial hunch was that rushing is a major
factor in determining the value fantasy success by quarterbacks.
ggplot() +
geom_jitter(
data=ALL_QB_FP,
aes(x=`FPTS/G`, y=R_ATT), color="grey") +
geom_text_repel(
data=ALL_QB_FP,
aes(x=`FPTS/G`, y=R_ATT, label=full_name)) +
geom_jitter(
data=ALL_QB_FP10,
groupOnX=TRUE,
aes(x=`FPTS/G`, y=R_ATT), color="red") +
labs(x="Fantasy Points Per Game", y="Rushing Attempts", title="Correlation Between Rushes and Fantasy Points Per Game by QBs", subtitle="**Data through Week 11**") +
theme_minimal()
Warning: Ignoring unknown parameters: groupOnX

#Note This first graph confirmed my initial hypothesis that there is
a significant correlation between rushing attempts and fantasy points
scored. However, in the next graphs, I had to chart some passing stats
in order to determine its accurary.
ggplot() +
geom_jitter(
data=ALL_QB_FP,
aes(x=`FPTS/G`, y=TotalDropbacks), color="grey") +
geom_text_repel(
data=ALL_QB_FP,
aes(x=`FPTS/G`, y=TotalDropbacks, label=full_name)) +
geom_jitter(
data=ALL_QB_FP10,
groupOnX=TRUE,
aes(x=`FPTS/G`, y=TotalDropbacks), color="red") +
labs(x="Fantasy Points Per Game", y="Dropbacks", title="Correlation Between Dropbacks and Fantasy Points Per Game by QBs", subtitle="**Data through Week 11**") +
theme_minimal()
Warning: Ignoring unknown parameters: groupOnX

#Note Based on this chart, it becomes clear that drop backs directly
correlates to fantasy points which seems obvious. The more chances you
have to make a play, the more points you are likely to tally.
ggplot() +
geom_jitter(
data=ALL_QB_FP,
aes(x=`FPTS/G`, y=Avg_QBEPA), color="grey") +
geom_text_repel(
data=ALL_QB_FP,
aes(x=`FPTS/G`, y=Avg_QBEPA, label=full_name)) +
geom_jitter(
data=ALL_QB_FP10,
groupOnX=TRUE,
aes(x=`FPTS/G`, y=Avg_QBEPA), color="red") +
labs(x="Fantasy Points Per Game", y="Average QB EPA", title="Correlation Between Average QB EPA and Fantasy Points Per Game by QBs", subtitle="**Data through Week 11**") +
theme_minimal()
Warning: Ignoring unknown parameters: groupOnX

#Note EPA is defined as expected points added. In this case QB EPA,
refers to points added by a QB with either their arms or legs and takes
into account yards per attempt, yards per rush, YAC, ETC to accurately
focus soley on the QB. Tua ranks lower in this metric because he is
often benefited by short passes turning into explosive plays because of
elite playmaker, as is Jimmy G.
ggplot() +
geom_jitter(
data=ALL_QB_FP,
aes(x=`FPTS/G`, y=ATT), color="grey") +
geom_text_repel(
data=ALL_QB_FP,
aes(x=`FPTS/G`, y=ATT, label=full_name)) +
geom_jitter(
data=ALL_QB_FP10,
groupOnX=TRUE,
aes(x=`FPTS/G`, y=ATT), color="red") +
labs(x="Fantasy Points Per Game", y="Attempts", title="Correlation Between Passing Attempts and Fantasy Points Per Game by QBs", subtitle="**Data through Week 11**") +
theme_minimal()
Warning: Ignoring unknown parameters: groupOnX

#Note Based on this data, there is no real correlation between passes
thrown and fantasy relevance this season. Mahomes, Burrow and Allen are
outliers, especially considering the pass volume of both Buffalo’s and
Kansas City’s offenses.
ggplot() +
geom_jitter(
data=ALL_QB_FP,
aes(x=`FPTS/G`, y=R_YDS), color="grey") +
geom_text_repel(
data=ALL_QB_FP,
aes(x=`FPTS/G`, y=R_YDS, label=full_name)) +
geom_jitter(
data=ALL_QB_FP10,
groupOnX=TRUE,
aes(x=`FPTS/G`, y=R_YDS), color="red") +
labs(x="Fantasy Points Per Game", y="Rushing Yards", title="Correlation Between Rushing Yards and Fantasy Points Per Game by QBs", subtitle="**Data through Week 11**") +
theme_minimal()
Warning: Ignoring unknown parameters: groupOnX

#Conclusion for QB Based on the four prior charts and sifting through
other possible correlations , I believe that rushing is the primary
determinant of success at the QB position, confirming my hypothesis.
What specifically clarified this concept to me was the differentiation
between attempts and dropbacks.
Attempts refers to the amount of passes thrown versus drop backs
which signify the amount of times they dropped back to pass. This is
because dropbacks, especially for mobile quarterbacks, allow the
opportunity for scrambling. In fantasy football, QBs recieve .1 point
per yard rushed, as compared to .04 points for every passing yard. For
passing touchdowns, QBs recieve 4 points as compared to 6 points for
rushing touchdowns.
Justin Fields is a prime example. Around the NFL, Fields is known for
his elite rushing but has struggled throwing the football early in his
career. However, despite sub par throwing numbers, the 2nd year QB has
emerged as an elite fantasy QB option primarily because of his legs.
Daniel Jones is also not known as an elite thrower, but his versatility
and volume in the run game make him a very viable.
Overall, it is clear that the days of picking a QB who does not
really use his legs are behind us in fantasy football. Grabbing an elite
rushing quarterback often means grabbing a a pretty good fantasy
quarterback. By adding top tier throwing with a good mix of running, you
venture into elite quarterback range. There are viable starting options
on both the running and passing side of the spectrum. However, if you
want an elite QB, you need a strong dosage of running.
#Tight Ends For tight ends in fantasy football, it’s either you have
an obviously good player or you’re rolling the dice in 2022. Especially
at tight end, where efficiency is the name of the game due to lesser
volume, explosive plays and touchdwons are typically the main dterminent
of success.
ggplot() +
geom_jitter(
data=ALL_TE_FP,
aes(x=`FPTS/G`, y=`Y/R`), color="grey") +
geom_text_repel(
data=ALL_TE_FP,
aes(x=`FPTS/G`, y=`Y/R`, label=full_name)) +
geom_jitter(
data=ALL_TE_FP10,
groupOnX=TRUE,
aes(x=`FPTS/G`, y=`Y/R`), color="red") +
labs(x="Fantasy Points Per Game", y="Yards per Reception", title="Correlation Between Yards per Receptions and Fantasy Points Per Game by Tight Ends", subtitle="**Data through Week 11**") +
theme_minimal()
Warning: Ignoring unknown parameters: groupOnX

#Note This data supports this idea. All of these tight ends are often
used vertically down the field and are extremely good at running after
the catch, meaning they capitalize on their opportunities.
ggplot() +
geom_jitter(
data=ALL_TE_FP,
aes(x=`FPTS/G`, y=`20+`), color="grey") +
geom_text_repel(
data=ALL_TE_FP,
aes(x=`FPTS/G`, y=`20+`, label=full_name)) +
geom_jitter(
data=ALL_TE_FP10,
groupOnX=TRUE,
aes(x=`FPTS/G`, y=`20+`), color="red") +
labs(x="Fantasy Points Per Game", y="Number of 20+ Yard Receptions", title="Correlation Between Number of 20 Yard Receptions and Fantasy Points Per Game by Tight Ends", subtitle="**Data through Week 11**") +
theme_minimal()
Warning: Ignoring unknown parameters: groupOnX

#Note It appears that a majority of the top 10 tight ends also fall
in the top 10 of number of 20+ yard receptions. This further confirms my
inital thought.
ggplot() +
geom_jitter(
data=ALL_TE_FP,
aes(x=`FPTS/G`, y=LG), color="grey") +
geom_text_repel(
data=ALL_TE_FP,
aes(x=`FPTS/G`, y=LG, label=full_name)) +
geom_jitter(
data=ALL_TE_FP10,
groupOnX=TRUE,
aes(x=`FPTS/G`, y=`LG`), color="red") +
labs(x="Fantasy Points Per Game", y="Longest Gain", title="Correlation Between Longest Gain this season and Fantasy Points Per Game by Tight Ends", subtitle="**Data through Week 11**") +
theme_minimal()
Warning: Ignoring unknown parameters: groupOnX

ggplot() +
geom_jitter(
data=ALL_TE_FP,
aes(x=`FPTS/G`, y=TD), color="grey") +
geom_text_repel(
data=ALL_TE_FP,
aes(x=`FPTS/G`, y=TD, label=full_name)) +
geom_jitter(
data=ALL_TE_FP10,
groupOnX=TRUE,
aes(x=`FPTS/G`, y=TD), color="red") +
labs(x="Fantasy Points Per Game", y="Touchdowns", title="Correlation Between Touchdowns and Fantasy Points Per Game by Tight Ends", subtitle="**Data through Week 11**") +
theme_minimal()
Warning: Ignoring unknown parameters: groupOnX

#Note Clearly, there is a correlation between touchdowns and fantasy
points. However, I feel that this is not the best indicator of success
at the tight end position though it factors.
#Conclusion Tight end has always been a wild card in fantasy
football, both in the drafting process and throughout the regular
season. However, this reality was magnified even more so in 2022 and
changes perspective on how the position should be valued. When Travis
Kelce was projected in the first round in PPR formats, some including
myself initially scoffed. However, based on the volatility of the
position it appears that guaranteeing elite performance from a small
group of elite tight ends may change drafting strategies moving
forward.
Furthermore, when evaluating tight ends specifically, it appears the
biggest correlation to fantasy success is explosive plays. Tight ends
tend receive less volume than other pass catchers. The players who can
maximize these opportunities clearly thrive and are players you want on
your team.
Another thing to note is competition for targets. Though YAC is king
for tight ends, volume never hurts. Players like Kelce, Andrews,
Hockenson, and Ertz are all elite talents that play in offenses who are
lacking elite playmkers on the outside. This is interesting because
these players are already explosive and are given more chances to be
explosive due to lesser talent at WR.
With all this being said, it would be wise to target an elite TE that
is a primary weapon in a good offense and is strong after the catch. In
fact, because of depth at other positions, there is a legitimate cases
that it is never too early to draft an elite tight end.
#Running Back First, I will analyze running specific categories
before specifically focusing on passing. For running backs, volume
appears to be your main target, especially when a large volume comes in
the passing games. However, all great running backs have a steady floor
as a rusher, elevating their ceiling with strong pass production.
ggplot() +
geom_jitter(
data=ALL_RB_FP,
aes(x=`FPTS/G`, y=TotalRushAttempts), color="grey") +
geom_text_repel(
data=ALL_RB_FP,
aes(x=`FPTS/G`, y=TotalRushAttempts, label=full_name)) +
geom_jitter(
data=ALL_RB_FP10,
groupOnX=TRUE,
aes(x=`FPTS/G`, y=TotalRushAttempts), color="red") +
labs(x="Fantasy Points Per Game", y="Total Rush Attempts", title="Correlation Between Rush Attempts and Fantasy Points Per Game by Running Backs", subtitle="**Data through Week 11**") +
theme_minimal()
Warning: Ignoring unknown parameters: groupOnX

#Note This chart tells you two main things. First, it clarifies that
indeed there is a massive correlation between volume and fantasy
strictly as a runner. Secondly, it clarifies that the best running backs
are dominant in their committees. Split backfields are death in fantasy
football so you are looking for high volume and a strong percentage of a
team’s uage.
ggplot() +
geom_jitter(
data=ALL_RB_FP,
aes(x=`FPTS/G`, y=YPC), color="grey") +
geom_text_repel(
data=ALL_RB_FP,
aes(x=`FPTS/G`, y=YPC, label=full_name)) +
geom_jitter(
data=ALL_RB_FP10,
groupOnX=TRUE,
aes(x=`FPTS/G`, y=YPC), color="red") +
labs(x="Fantasy Points Per Game", y="Yards Per Carry", title="Correlation Between Yards per Carry and Fantasy Points Per Game by Running Backs", subtitle="**Data through Week 11**") +
theme_minimal()
Warning: Ignoring unknown parameters: groupOnX

#Note Interestingly there is not a strong correlation between yards
per carry and FPPG. Tony Pollard for example, is elite in terms of YPC,
however the Cowboys are deadset on feeding Zeke which prevents Pollard
from being elite due to a lack of volume. You want to target high YPC
runners with a solid volume floor.
ggplot() +
geom_jitter(
data=ALL_RB_FP,
aes(x=`FPTS/G`, y=`20+`), color="grey") +
geom_text_repel(
data=ALL_RB_FP,
aes(x=`FPTS/G`, y=`20+`, label=full_name)) +
geom_jitter(
data=ALL_RB_FP10,
groupOnX=TRUE,
aes(x=`FPTS/G`, y=`20+`), color="red") +
labs(x="Fantasy Points Per Game", y="Number of 20+ Yard Runs", title="Correlation Between 20+ Yard Runs and Fantasy Points Per Game by Running Backs", subtitle="**Data through Week 11**") +
theme_minimal()
Warning: Ignoring unknown parameters: groupOnX

#Note This graph points to a theme of volume. The best running backs
have the most explosive runs which seems obvious. However, this is
because their teams understand their home run potential, giving them
ample opportunities to break a long run. The players outside the top 10
who have a lot of big runs had split backfields for a majority of the
season, giving them less oppurutnity despite their obvious knack for
it.
So many times we have seen a great running back struggle for
stretches of games before pulling a 60-yard touchdown run out of his
hat. The more chances you are given, the more likely you are to break
free and gain points.
ggplot() +
geom_jitter(
data=ALL_RB_FP,
aes(x=`FPTS/G`, y=`TD...6`), color="grey") +
geom_text_repel(
data=ALL_RB_FP,
aes(x=`FPTS/G`, y=`TD...6`, label=full_name)) +
geom_jitter(
data=ALL_RB_FP10,
groupOnX=TRUE,
aes(x=`FPTS/G`, y=`TD...6`), color="red") +
labs(x="Fantasy Points Per Game", y="Touchdowns", title="Correlation Between Touchdowns and Fantasy Points Per Game by Running Backs", subtitle="**Data through Week 11**") +
theme_minimal()
Warning: Ignoring unknown parameters: groupOnX

#Note Touchdowns are a direct correlation to success as well. Jamaal
Williams proves something interesting however as a low volume runner
with the lead league in touchdowns. This is because he receives a
majority of the goal-line work. Goal-line volume is a clear correlation
to fantasy points, continuing a trend at running back.
ggplot() +
geom_jitter(
data=ALL_RB_FP,
aes(x=`FPTS/G`, y= TGT), color="grey") +
geom_text_repel(
data=ALL_RB_FP,
aes(x=`FPTS/G`, y=TGT, label=full_name)) +
geom_jitter(
data=ALL_RB_FP10,
groupOnX=TRUE,
aes(x=`FPTS/G`, y=TGT), color="red") +
labs(x="Fantasy Points Per Game", y="Targets", title="Correlation Between Targets and Fantasy Points Per Game by Running Backs", subtitle="**Data through Week 11**") +
theme_minimal()
Warning: Ignoring unknown parameters: groupOnX

#Note Interestingly, it seems that targets are less correlated to
fantasy success unless you are Austin Eckeler or CMC, receiving a
massive passing volume. However, a majority of the top running backs
happen to fall in the upper regions of targets.
ggplot() +
geom_jitter(
data=ALL_RB_FP,
aes(x=`FPTS/G`, y=REC), color="grey") +
geom_text_repel(
data=ALL_RB_FP,
aes(x=`FPTS/G`, y=REC, label=full_name)) +
geom_jitter(
data=ALL_RB_FP10,
groupOnX=TRUE,
aes(x=`FPTS/G`, y=REC), color="red") +
labs(x="Fantasy Points Per Game", y="Receptions", title="Correlation Between Receptions and Fantasy Points Per Game by Running Backs", subtitle="**Data through Week 11**") +
theme_minimal()
Warning: Ignoring unknown parameters: groupOnX

#Note More targets mean more receptions. VOLUME! VOLUME! VOLUME!
ggplot() +
geom_jitter(
data=ALL_RB_FP,
aes(x=`FPTS/G`, y=`Y/R`), color="grey") +
geom_text_repel(
data=ALL_RB_FP,
aes(x=`FPTS/G`, y=`Y/R`, label=full_name)) +
geom_jitter(
data=ALL_RB_FP10,
groupOnX=TRUE,
aes(x=`FPTS/G`, y=`Y/R`), color="red") +
labs(x="Fantasy Points Per Game", y="Yards per Reception", title="Correlation Between Yards per Reception and Fantasy Points Per Game by Running Backs", subtitle="**Data through Week 11**") +
theme_minimal()
Warning: Ignoring unknown parameters: groupOnX

#Note Yards per reception is clearly a vague stat, again likely
having to be correlated to volume.
ggplot() +
geom_jitter(
data=ALL_RB_FP,
aes(x=`FPTS/G`, y=`TD...11`), color="grey") +
geom_text_repel(
data=ALL_RB_FP,
aes(x=`FPTS/G`, y=`TD...11`, label=full_name)) +
geom_jitter(
data=ALL_RB_FP10,
groupOnX=TRUE,
aes(x=`FPTS/G`, y=`TD...11`), color="red") +
labs(x="Fantasy Points Per Game", y="Receiving Touchdowns", title="Correlation Between Receiving Touchdowns and Fantasy Points Per Game by Running Backs", subtitle="**Data through Week 11**") +
theme_minimal()
Warning: Ignoring unknown parameters: groupOnX

#Note Not much correlation between receiving touchdowns and FPPG.
#Conclusion Overall, my initial hypothesis was right. Volume is
absolutely key.
- Target running backs with limited competition in their backfield.
This results in a more rush attempts, more targets, and more
oppurunities to make big plays.
-Running backs who receive elite usgae and pretty good passing volume
are elite running backs.
-Passing volume alone is not even close to enough to maintain fantasy
relevance.
Avoid players in split backfields, especailly when their role is
mainly as a pass catcher.
Goaline usage is massive for running backs as TD’s correlate
directly to increased fantasy points.
#Receivers I know that volume is important for WRs as well, however I
want to determine which type of volume is best.
ggplot() +
geom_jitter(
data=ALL_WR_FP,
aes(x=`FPTS/G`, y=Total_AirYards), color="grey") +
geom_text_repel(
data=ALL_WR_FP,
aes(x=`FPTS/G`, y=Total_AirYards, label=full_name)) +
geom_jitter(
data=ALL_WR_FP10,
groupOnX=TRUE,
aes(x=`FPTS/G`, y=Total_AirYards), color="red") +
labs(x="Fantasy Points Per Game", y="Total Air Yards", title="Correlation Between Total Air Yards and Fantasy Points Per Game by Wide Receivers", subtitle="**Data through Week 11**") +
theme_minimal()
Warning: Ignoring unknown parameters: groupOnX

#Note Total air yards is representative of either fewer but longer
targets or a lot of passes thrown a players way in general. It makes a
lot of sense that some of the best receivers have the most total air
yards. The elite receivers on this list not in the top percentage of air
yards have missed a significant chunk of games, proving that air yards
are vital.
ggplot() +
geom_jitter(
data=ALL_WR_FP,
aes(x=`FPTS/G`, y=Avg_AirYards), color="grey") +
geom_text_repel(
data=ALL_WR_FP,
aes(x=`FPTS/G`, y=Avg_AirYards, label=full_name)) +
geom_jitter(
data=ALL_WR_FP10,
groupOnX=TRUE,
aes(x=`FPTS/G`, y=Avg_AirYards), color="red") +
labs(x="Fantasy Points Per Game", y="Average Air Yards", title="Correlation Between Average Air Yards and Fantasy Points Per Game by Wide Receivers", subtitle="**Data through Week 11**") +
theme_minimal()
Warning: Ignoring unknown parameters: groupOnX

#Note This graph is similar to depth of target. While the best
receivers are pretty high up there in average air yards, none appear to
be elite in the category as their volume superseeds it.
ggplot() +
geom_jitter(
data=ALL_WR_FP,
aes(x=`FPTS/G`, y=Avg__YAC), color="grey") +
geom_text_repel(
data=ALL_WR_FP,
aes(x=`FPTS/G`, y=Avg__YAC, label=full_name)) +
geom_jitter(
data=ALL_WR_FP10,
groupOnX=TRUE,
aes(x=`FPTS/G`, y=Avg__YAC), color="red") +
labs(x="Fantasy Points Per Game", y="Average Yards per Catch", title="Correlation Between Average Yards per Catch and Fantasy Points Per Game by Wide Receivers", subtitle="**Data through Week 11**") +
theme_minimal()
Warning: Ignoring unknown parameters: groupOnX

#Note It seems that YPC is a more random statisitc in determine
fantasy success at WR.
ggplot() +
geom_jitter(
data=ALL_WR_FP,
aes(x=`FPTS/G`, y=Avg_ReceivingYds), color="grey") +
geom_text_repel(
data=ALL_WR_FP,
aes(x=`FPTS/G`, y=Avg_ReceivingYds, label=full_name)) +
geom_jitter(
data=ALL_WR_FP10,
groupOnX=TRUE,
aes(x=`FPTS/G`, y=Avg_ReceivingYds), color="red") +
labs(x="Fantasy Points Per Game", y="Average Receiving Yards", title="Correlation Between Average Receiving Yards and Fantasy Points Per Game by Wide Receivers", subtitle="**Data through Week 11**") +
theme_minimal()
Warning: Ignoring unknown parameters: groupOnX

#Note Again less of a correlation.
ggplot() +
geom_jitter(
data=ALL_WR_FP,
aes(x=`FPTS/G`, y=TotalReceivingYds), color="grey") +
geom_text_repel(
data=ALL_WR_FP,
aes(x=`FPTS/G`, y=TotalReceivingYds, label=full_name)) +
geom_jitter(
data=ALL_WR_FP10,
groupOnX=TRUE,
aes(x=`FPTS/G`, y=TotalReceivingYds), color="red") +
labs(x="Fantasy Points Per Game", y="Total Receiving Yards", title="Correlation Between Total Receiving Yards and Fantasy Points Per Game by Wide Receivers", subtitle="**Data through Week 11**") +
theme_minimal()
Warning: Ignoring unknown parameters: groupOnX

#Conclusion Overall, even more so than running backs, volume is key
at receiver. You want to target receivers in offenses who throw the ball
a lot, have a good quarterback and are heavily featured in their
offense. In fact, most of the elite receivers have offenses built around
either their talent or their quarterbacks talent. Chase elite players in
a clear and defined role.
#Overall Conclusions While fantasy is a majority luck, understanding
these concepts will allow fantasy players to focus on specific markers
to consider when drafting, making trades, determining who to start or
who to grab off the waivers. However, for this final analysis, I will
mainly focus on drafting purposes.
#Drafting QBs If you are going to draft a quarterback early in the
draft, they better be named Patrick Mahomes or offer either elite
passing with a decent running floor or an elite running quarterback.
#Drafting Running Backs -Chase volume as a runner -Target players who
are clearly the main guy and will receive a majority of the running back
snaps. - In 2022, running backs were a dime a dozen. Make sure if you
draft a running back early, you are buying into a player who you know is
worthy of the volume. - If a running back is known for his utilization
in the passing game and is projected for a bigger role as a runner, they
could be a sleeper. -You need running backs who receive goal-line work.
Volume and yards alone are not enough for sustainability. -Avoid
anything less than a 60/40 split of carries.
#Drafting Tight Ends -If there is an elite guy there, go get him. I
know that only refers to about four players, but this just shows how
large the drop-off is. - Taking Kelce at any point in the first round is
understandable and maybe even wise moving forward. - Target explosive
players who are targeted down the field often and thrive on YAC.
#Drafting WRs - At the top of the draft, aim for elite talents, in
elite offenses with good quarterbacks, don’t over think it.
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKTm93IHRoYXQgYWxsIHRoZSBkYXRhIGlzIGxvYWRlZCBpbiBmb3IgZWFjaCBwb3NpdGlvbiwgaW5jbHVkaW5nIGZhbnRhc3kgcG9pbnQgdmFsdWVzLCBJIGNhbiBvZmZpY2lhbGx5IGRpZyBpbiB0byBkZXRlcm1pbmUgd2hpY2ggc3RhdHMgb3IgYXJlYXMgYXJlIG1vc3QgcHJlZGljdGl2ZSBpbiBkZXRlcm1pbmluZyBmYW50YXN5IGZvb3RiYWxsIGFjY2Vzcy4gVGhlIGFuc3dlciBtYXkgdmFyeSBieSBwb3NpdGlvbiBidXQgSSBwbGFuIG9uIGRpZ2dpbmcgaW4gZGVlcGx5LCBtYWtpbmcgYSBidW5jaCBvZiBkaWZmZXJlbnQgdmlzdWFsaXphdGlvbnMgdG8gZmluZCBzb21lIHNvcnQgb2YgY29uc2Vuc3VzIHRoYXQgY2FuIGJlIHVzZWQgZm9yIGRyYWZ0aW5nIHRlYW1zIG5leHQgc2Vhc29uLiBBZnRlciBjcmVhdGluZyBkYXRhIHNldHMsIGpvaW5pbmcgdGhlbSBieSBwb3NpdGlvbiBhbmQgdGhlIGNvZGUgZm9yIHRhcmdldHMgd29ya2luZyBub3cgc29tZWhvdywgSSBmZWVsIGFzIGlmIEkgYWRkcmVzc2VkIGEgbWFqb3JpdHkgb2YgdGhlIGlzc3VlcyBJIGhhZCBwcmV2aW91c2x5IGJlZW4gZmFjaW5nLiBJIGxvb2sgZm9yd2FyZCB0byBkaWdnaW5nIGluIGZ1cnRoZXIuCgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkobmZscmVhZHIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdnYWx0KQpsaWJyYXJ5KGdnYmVlc3dhcm0pCmxpYnJhcnkoZ2dyZXBlbCkKYGBgCmBgYHtyfQpORkw8LSBsb2FkX3BicCgKICBzZWFzb25zID0gbW9zdF9yZWNlbnRfc2Vhc29uKCksCiAgZmlsZV90eXBlID0gZ2V0T3B0aW9uKCJuZmxyZWFkci5wcmVmZXIiLCBkZWZhdWx0ID0gInJkcyIpCikKYGBgCgpgYGB7cn0KTkZMUm9zdGVyczwtIGxvYWRfcm9zdGVycygKICBzZWFzb25zID0gbW9zdF9yZWNlbnRfc2Vhc29uKHJvc3RlciA9IFRSVUUpLAogIGZpbGVfdHlwZSA9IGdldE9wdGlvbigibmZscmVhZHIucHJlZmVyIiwgZGVmYXVsdCA9ICJyZHMiKQopCmBgYAoKYGBge3J9Ck5GTCA8LSBORkwgJT4lIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYyksIH4gcmVwbGFjZV9uYSguLCAwKSkpCmBgYAoKYGBge3J9CldSXzU1IDwtIHJlYWRfY3N2KCJ+L2NvZGUvbWNoYXJsZXMzMTcuZ2l0aHViLmlvL1dSNTUuY3N2IikKYGBgCmBgYHtyfQpSQl81NSA8LSByZWFkX2Nzdigifi9jb2RlL21jaGFybGVzMzE3LmdpdGh1Yi5pby9SQjU1LmNzdiIpCmBgYApgYGB7cn0KVEVfMjQgPC0gcmVhZF9jc3YoIn4vY29kZS9tY2hhcmxlczMxNy5naXRodWIuaW8vVEUyNC5jc3YiKQpgYGAKYGBge3J9CgpRQjI0IDwtIHJlYWRfY3N2KCJ+L2NvZGUvbWNoYXJsZXMzMTcuZ2l0aHViLmlvL1FCMjQuY3N2IikKYGBgCgpgYGB7cn0KVEUgPC0gTkZMICU+JSAKICAgZmlsdGVyKGZhbnRhc3lfcGxheWVyX25hbWUgPT0gIkQuR29lZGVydCIgfCBmYW50YXN5X3BsYXllcl9uYW1lID09ICJELlNjaHVsdHoiICkKYGBgCmBgYHtyfQpNeVRFcyA8LSBORkwgJT4lIApmaWx0ZXIoZmFudGFzeV9wbGF5ZXJfaWQgPT0gIjAwLTAwMzQzNTEiIHwgZmFudGFzeV9wbGF5ZXJfaWQgPT0gIjAwLTAwMzQzODMiICkgJT4lIApncm91cF9ieShmYW50YXN5X3BsYXllcl9pZCwgZmFudGFzeV9wbGF5ZXJfbmFtZSkgJT4lIAogIHN1bW1hcmlzZShUb3RhbFJlY2VpdmluZ1lkcyA9IHN1bShyZWNlaXZpbmdfeWFyZHMpLCBBdmdfUmVjZWl2aW5nWWRzID0gbWVhbihyZWNlaXZpbmdfeWFyZHMpLCBUb3RhbF9BaXJZYXJkcz0gc3VtKGFpcl95YXJkcyksIEF2Z19BaXJZYXJkcz0gbWVhbihhaXJfeWFyZHMpLCBBdmdfX1lBQyA9IG1lYW4gKHlhcmRzX2FmdGVyX2NhdGNoKSwgVG90YWxfWUFDID0gc3VtICh5YXJkc19hZnRlcl9jYXRjaCksIEF2Z19BaXJFUEEgPSBtZWFuIChhaXJfZXBhKSwgVG90YWxfQWlyRVBBID0gc3VtKGFpcl9lcGEpLCBBdmdfWUFDRVBBID1tZWFuICh5YWNfZXBhKSwgVG90YWxfWWFjRVBBID0gc3VtKHlhY19lcGEpLCBBdmdfY29tcF9haXJfZXBhID0gbWVhbihjb21wX2Fpcl9lcGEpLCBUb3RhbF9jb21wX2Fpcl9lcGEgPSBzdW0gKGNvbXBfYWlyX2VwYSksIFRvdGFsX1lBQ19Db21wID0gc3VtKGNvbXBfeWFjX2VwYSksIEF2Z19ZQUNfQ29tcCA9IG1lYW4oY29tcF95YWNfZXBhKSwgVG90YWxfWUFDX1dQQSA9IHN1bSh5YWNfd3BhKSwgQXZnX1lBQ19XUEEgPSBtZWFuKHlhY193cGEpKQpgYGAKCgpgYGB7cn0KTXlRQiA8LSBORkwgJT4lIAogIGZpbHRlcihwYXNzZXJfcGxheWVyX2lkID09ICIwMC0wMDM2NDQyIiklPiUgCiAgZ3JvdXBfYnkocGFzc2VyX3BsYXllcl9pZCwgbmFtZSklPiUgCnN1bW1hcmlzZShBdmdfY29tcF9haXJfZXBhID0gbWVhbihjb21wX2Fpcl9lcGEpLCBUb3RhbF9jb21wX2Fpcl9lcGEgPSBzdW0gKGNvbXBfYWlyX2VwYSksIFRvdGFsX3Bhc3NfdG91Y2hkb3duID0gc3VtIChwYXNzX3RvdWNoZG93biksIFRvdGFsX2NvbXBsZXRlX3Bhc3MgPSBzdW0oY29tcGxldGVfcGFzcyksIFRvdGFsX1Bhc3NfYXR0ZW1wdCA9IHN1bShwYXNzX2F0dGVtcHQpLCBJbnRlcmNlcHRpb25zID0gc3VtKGludGVyY2VwdGlvbiksIFRvdGFsUUJFUEEgPXN1bShxYl9lcGEpLCBBdmdfUUJFUEEgPSBtZWFuKHFiX2VwYSksIEF2Z19wYXNzX29lID0gbWVhbihwYXNzX29lKSwgQXZnX2NvbXBfYWlyX2VwYSA9IG1lYW4oY29tcF9haXJfZXBhKSwgVG90YWxfY29tcF9haXJfZXBhID0gc3VtKGNvbXBfYWlyX2VwYSksIFRvdGFsRHJvcGJhY2tzPSBzdW0gKHFiX2Ryb3BiYWNrKSkKYGBgCgoKYGBge3J9ClFCX2J5X1dlZWs8LSBORkwlPiUgCiAgZmlsdGVyKHBhc3Nlcl9wbGF5ZXJfaWQgPT0gIjAwLTAwMzY0NDIiKSU+JSAKICBncm91cF9ieShwYXNzZXJfcGxheWVyX2lkLCB3ZWVrLCBuYW1lKSU+JSAKc3VtbWFyaXNlKEF2Z19jb21wX2Fpcl9lcGEgPSBtZWFuKGNvbXBfYWlyX2VwYSksIFRvdGFsX2NvbXBfYWlyX2VwYSA9IHN1bSAoY29tcF9haXJfZXBhKSwgVG90YWxfcGFzc190b3VjaGRvd24gPSBzdW0gKHBhc3NfdG91Y2hkb3duKSwgVG90YWxfY29tcGxldGVfcGFzcyA9IHN1bShjb21wbGV0ZV9wYXNzKSwgVG90YWxfUGFzc19hdHRlbXB0ID0gc3VtKHBhc3NfYXR0ZW1wdCksIFRvdGFsUUJFUEEgPXN1bShxYl9lcGEpLCBBdmdfUUJFUEEgPSBtZWFuKHFiX2VwYSksIEF2Z19wYXNzX29lID0gbWVhbihwYXNzX29lKSwgQXZnX2NvbXBfYWlyX2VwYSA9IG1lYW4oY29tcF9haXJfZXBhKSwgVG90YWxfY29tcF9haXJfZXBhID0gc3VtKGNvbXBfYWlyX2VwYSksIFRvdGFsRHJvcGJhY2tzPSBzdW0gKHFiX2Ryb3BiYWNrKSwgSW50ZXJjZXB0aW9ucyA9IHN1bShpbnRlcmNlcHRpb24pLCBHYW1lc1BsYXllZCA9IG5fZGlzdGluY3QoZ2FtZV9pZCkpCmBgYApgYGB7cn0KUUJfUnVzaGluZyA8LSBORkwgJT4lIAogIGZpbHRlcihmYW50YXN5X2lkID09ICIwMC0wMDM2NDQyIikgJT4lIAogIGZpbHRlcihydXNoX2F0dGVtcHQgPT0gMSkgJT4lIAogIG11dGF0ZShydXNoaW5nX3lhcmRzID0gcmVwbGFjZV9uYShydXNoaW5nX3lhcmRzLCAwKSkgJT4lIAogIGdyb3VwX2J5KGZhbnRhc3lfaWQsIG5hbWUpICU+JSAKICBzdW1tYXJpc2UoVG90YWxSdXNoQXR0ZW1wdHMgPSBzdW0ocnVzaF9hdHRlbXB0KSwgVG90YWxSdXNoWWFyZHMgPSBzdW0ocnVzaGluZ195YXJkcyksIEdhbWVzUGxheWVkID0gbl9kaXN0aW5jdChnYW1lX2lkKSkKYGBgCmBgYHtyfQpRQk92ZXJhbGwgPC0gTXlRQiAlPiUgCiAgaW5uZXJfam9pbihRQl9SdXNoaW5nLCBieT0gIm5hbWUiKQpgYGAKCmBgYHtyfQpRQl9SdXNoaW5nX1dlZWtseTwtIE5GTCAlPiUgCiAgZmlsdGVyKHJ1c2hlciA9PSAiSi5CdXJyb3ciKSAlPiUgCiAgZ3JvdXBfYnkocnVzaGVyLCBuYW1lLCB3ZWVrKSAlPiUgCiAgc3VtbWFyaXNlKFRvdGFsUnVzaEF0dGVtcHRzID0gc3VtKHJ1c2hfYXR0ZW1wdCksIFRvdGFsUnVzaFlhcmRzID0gc3VtKHJ1c2hpbmdfeWFyZHMpKQpgYGAKYGBge3J9ClFCX092ZXJhbGxfV2Vla2x5IDwtIFFCX2J5X1dlZWsgJT4lIAogIGlubmVyX2pvaW4oUUJfUnVzaGluZ19XZWVrbHksIGJ5PSAibmFtZSIpCmBgYAoKYGBge3J9Ck15V1IgPC0gTkZMICU+JSAKICAgZmlsdGVyKGZhbnRhc3lfcGxheWVyX2lkID09ICIwMC0wMDMwNTY0IiB8IGZhbnRhc3lfcGxheWVyX2lkID09ICIwMC0wMDM2NDEwIiB8IGZhbnRhc3lfcGxheWVyX2lkID09ICIwMC0wMDM3MjM5IiB8IGZhbnRhc3lfcGxheWVyX2lkID09ICIwMC0wMDMzNTM2IiB8IGZhbnRhc3lfcGxheWVyX2lkID09ICIwMC0wMDM3MjQ3IiB8IGZhbnRhc3lfcGxheWVyX2lkID09ICIwMC0wMDM2OTg4IikgJT4lIAogIGdyb3VwX2J5KGZhbnRhc3lfcGxheWVyX2lkLCBmYW50YXN5X3BsYXllcl9uYW1lKSAlPiUgCiAgc3VtbWFyaXNlIChUb3RhbF9BaXJZYXJkcz0gc3VtKGFpcl95YXJkcyksIEF2Z19BaXJZYXJkcz0gbWVhbihhaXJfeWFyZHMpLCBBdmdfX1lBQyA9IG1lYW4gKHlhcmRzX2FmdGVyX2NhdGNoKSwgVG90YWxfWUFDID0gc3VtICh5YXJkc19hZnRlcl9jYXRjaCksIEF2Z19BaXJFUEEgPSBtZWFuIChhaXJfZXBhKSwgVG90YWxfQWlyRVBBID0gc3VtKGFpcl9lcGEpLCBBdmdfWUFDRVBBID1tZWFuICh5YWNfZXBhKSwgVG90YWxfWWFjRVBBID0gc3VtKHlhY19lcGEpLCBBdmdfY29tcF9haXJfZXBhID0gbWVhbihjb21wX2Fpcl9lcGEpLCBUb3RhbF9jb21wX2Fpcl9lcGEgPSBzdW0gKGNvbXBfYWlyX2VwYSksIFRvdGFsX1lBQ19Db21wID0gc3VtKGNvbXBfeWFjX2VwYSksIEF2Z19ZQUNfQ29tcCA9IG1lYW4oY29tcF95YWNfZXBhKSwgVG90YWxfWUFDX1dQQSA9IHN1bSh5YWNfd3BhKSwgQXZnX1lBQ19XUEEgPSBtZWFuKHlhY193cGEpLFRvdGFsUmVjZWl2aW5nWWRzID0gc3VtKHJlY2VpdmluZ195YXJkcyksIEF2Z19SZWNlaXZpbmdZZHMgPSBtZWFuKHJlY2VpdmluZ195YXJkcyksIFRvdGFsRVBBID0gc3VtKGVwYSksIFRvdGFsRXhwZWN0ZWRZQUNfRVBBID0gc3VtICh4eWFjX2VwYSksQXZnRXhwZWN0ZWRZQUNfRVBBID0gbWVhbiAoeHlhY19lcGEpLCBHYW1lc1BsYXllZCA9IG5fZGlzdGluY3QoZ2FtZV9pZCkpCmBgYAoKCgpgYGB7cn0KV1JfV2Vla2x5IDwtIE5GTCAlPiUgCiBmaWx0ZXIoZmFudGFzeV9wbGF5ZXJfaWQgPT0gIjAwLTAwMzA1NjQiIHwgZmFudGFzeV9wbGF5ZXJfaWQgPT0gIjAwLTAwMzY0MTAiIHwgZmFudGFzeV9wbGF5ZXJfaWQgPT0gIjAwLTAwMzcyMzkiIHwgZmFudGFzeV9wbGF5ZXJfaWQgPT0gIjAwLTAwMzM1MzYiIHwgZmFudGFzeV9wbGF5ZXJfaWQgPT0gIjAwLTAwMzcyNDciIHwgZmFudGFzeV9wbGF5ZXJfaWQgPT0gIjAwLTAwMzY5ODgiKSAlPiUgCiAgZ3JvdXBfYnkoZmFudGFzeV9wbGF5ZXJfaWQsIGZhbnRhc3lfcGxheWVyX25hbWUsIHdlZWspICU+JSAKICBzdW1tYXJpc2UgKFRvdGFsX0FpcllhcmRzPSBzdW0oYWlyX3lhcmRzKSwgQXZnX0FpcllhcmRzPSBtZWFuKGFpcl95YXJkcyksIEF2Z19fWUFDID0gbWVhbiAoeWFyZHNfYWZ0ZXJfY2F0Y2gpLCBUb3RhbF9ZQUMgPSBzdW0gKHlhcmRzX2FmdGVyX2NhdGNoKSwgQXZnX0FpckVQQSA9IG1lYW4gKGFpcl9lcGEpLCBUb3RhbF9BaXJFUEEgPSBzdW0oYWlyX2VwYSksIEF2Z19ZQUNFUEEgPW1lYW4gKHlhY19lcGEpLCBUb3RhbF9ZYWNFUEEgPSBzdW0oeWFjX2VwYSksIEF2Z19jb21wX2Fpcl9lcGEgPSBtZWFuKGNvbXBfYWlyX2VwYSksIFRvdGFsX2NvbXBfYWlyX2VwYSA9IHN1bSAoY29tcF9haXJfZXBhKSwgVG90YWxfWUFDX0NvbXAgPSBzdW0oY29tcF95YWNfZXBhKSwgQXZnX1lBQ19Db21wID0gbWVhbihjb21wX3lhY19lcGEpLCBUb3RhbF9ZQUNfV1BBID0gc3VtKHlhY193cGEpLCBBdmdfWUFDX1dQQSA9IG1lYW4oeWFjX3dwYSksIFRvdGFsRVBBID0gc3VtKGVwYSksIFRvdGFsRXhwZWN0ZWRZQUNfRVBBID0gc3VtICh4eWFjX2VwYSksQXZnRXhwZWN0ZWRZQUNfRVBBID0gbWVhbiAoeHlhY19lcGEpLCBUb3RhbFlhcmRzR2FpbmVkID0gc3VtKHlhcmRzX2dhaW5lZCksIEdhbWVzUGxheWVkID0gbl9kaXN0aW5jdChnYW1lX2lkKSkKYGBgCmBgYHtyfQpXUl9UaHJvdWdoV2VlazQgPC0gTkZMICU+JSAKICAgZmlsdGVyKGZhbnRhc3lfcGxheWVyX2lkID09ICIwMC0wMDMzOTIxIiB8IGZhbnRhc3lfcGxheWVyX2lkID09ICIwMC0wMDM0NzY0IiB8IGZhbnRhc3lfcGxheWVyX2lkID09ICIwMC0wMDM2OTEzIiB8IGZhbnRhc3lfcGxheWVyX2lkID09ICIwMC0wMDM2OTYzIiB8IGZhbnRhc3lfcGxheWVyX2lkID09ICIwMC0wMDM2MjUyIiwgd2VlayA8PSA0KSAlPiUgCiAgZ3JvdXBfYnkoZmFudGFzeV9wbGF5ZXJfaWQsIGZhbnRhc3lfcGxheWVyX25hbWUpICU+JSAKICBzdW1tYXJpc2UgKFRvdGFsX0FpcllhcmRzPSBzdW0oYWlyX3lhcmRzKSwgQXZnX0FpcllhcmRzPSBtZWFuKGFpcl95YXJkcyksIEF2Z19fWUFDID0gbWVhbiAoeWFyZHNfYWZ0ZXJfY2F0Y2gpLCBUb3RhbF9ZQUMgPSBzdW0gKHlhcmRzX2FmdGVyX2NhdGNoKSwgQXZnX0FpckVQQSA9IG1lYW4gKGFpcl9lcGEpLCBUb3RhbF9BaXJFUEEgPSBzdW0oYWlyX2VwYSksIEF2Z19ZQUNFUEEgPW1lYW4gKHlhY19lcGEpLCBUb3RhbF9ZYWNFUEEgPSBzdW0oeWFjX2VwYSksIEF2Z19jb21wX2Fpcl9lcGEgPSBtZWFuKGNvbXBfYWlyX2VwYSksIFRvdGFsX2NvbXBfYWlyX2VwYSA9IHN1bSAoY29tcF9haXJfZXBhKSwgVG90YWxfWUFDX0NvbXAgPSBzdW0oY29tcF95YWNfZXBhKSwgQXZnX1lBQ19Db21wID0gbWVhbihjb21wX3lhY19lcGEpLCBUb3RhbF9ZQUNfV1BBID0gc3VtKHlhY193cGEpLCBBdmdfWUFDX1dQQSA9IG1lYW4oeWFjX3dwYSksIFRvdGFsRVBBID0gc3VtKGVwYSksIFRvdGFsRXhwZWN0ZWRZQUNfRVBBID0gc3VtICh4eWFjX2VwYSksQXZnRXhwZWN0ZWRZQUNfRVBBID0gbWVhbiAoeHlhY19lcGEpLCBUb3RhbFlhcmRzR2FpbmVkID0gc3VtKHlhcmRzX2dhaW5lZCksIEdhbWVzUGxheWVkID0gbl9kaXN0aW5jdChnYW1lX2lkKSkKYGBgCgoKCgoKCmBgYHtyfQpNeVJCX3JlY2VpdmluZzwtIE5GTCAlPiUgCiAgZmlsdGVyKGZhbnRhc3lfcGxheWVyX2lkID09ICIwMC0wMDM2MjIzIiB8IGZhbnRhc3lfcGxheWVyX2lkID09ICIwMC0wMDM1NzAwIiB8IGZhbnRhc3lfcGxheWVyX2lkID09ICIwMC0wMDM2OTI0IiB8IGZhbnRhc3lfcGxheWVyX2lkID09ICIwMC0wMDM2Mjc1IiklPiUgCiAgZ3JvdXBfYnkoZmFudGFzeV9wbGF5ZXJfaWQsIGZhbnRhc3lfcGxheWVyX25hbWUpICU+JSAKICBzdW1tYXJpc2UoVG90YWxSZWNlaXZpbmdZZHMgPSBzdW0ocmVjZWl2aW5nX3lhcmRzKSwgQXZnX1JlY2VpdmluZ1lkcyA9IG1lYW4ocmVjZWl2aW5nX3lhcmRzKSwgVG90YWxfQWlyWWFyZHM9IHN1bShhaXJfeWFyZHMpLCBBdmdfQWlyWWFyZHM9IG1lYW4oYWlyX3lhcmRzKSwgQXZnX19ZQUMgPSBtZWFuICh5YXJkc19hZnRlcl9jYXRjaCksIFRvdGFsX1lBQyA9IHN1bSAoeWFyZHNfYWZ0ZXJfY2F0Y2gpLCBBdmdfQWlyRVBBID0gbWVhbiAoYWlyX2VwYSksIFRvdGFsX0FpckVQQSA9IHN1bShhaXJfZXBhKSwgQXZnX1lBQ0VQQSA9bWVhbiAoeWFjX2VwYSksIFRvdGFsX1lhY0VQQSA9IHN1bSh5YWNfZXBhKSwgQXZnX2NvbXBfYWlyX2VwYSA9IG1lYW4oY29tcF9haXJfZXBhKSwgVG90YWxfY29tcF9haXJfZXBhID0gc3VtIChjb21wX2Fpcl9lcGEpLCBUb3RhbF9ZQUNfQ29tcCA9IHN1bShjb21wX3lhY19lcGEpLCBBdmdfWUFDX0NvbXAgPSBtZWFuKGNvbXBfeWFjX2VwYSksIFRvdGFsX1lBQ19XUEEgPSBzdW0oeWFjX3dwYSksIEF2Z19ZQUNfV1BBID0gbWVhbih5YWNfd3BhKSwgVG90YWxFUEEgPSBzdW0oZXBhKSwgVG90YWxFeHBlY3RlZFlBQ19FUEEgPSBzdW0gKHh5YWNfZXBhKSxBdmdFeHBlY3RlZFlBQ19FUEEgPSBtZWFuICh4eWFjX2VwYSksIFRvdGFsWWFyZHNHYWluZWQgPSBzdW0oeWFyZHNfZ2FpbmVkKSwgR2FtZXNQbGF5ZWQgPSBuX2Rpc3RpbmN0KGdhbWVfaWQpKQpgYGAKCmBgYHtyfQpNeVJCPC0gTkZMICU+JSAKICAgZmlsdGVyKGZhbnRhc3lfcGxheWVyX2lkID09ICIwMC0wMDM2MjIzIiB8IGZhbnRhc3lfcGxheWVyX2lkID09ICIwMC0wMDM1NzAwIiB8IGZhbnRhc3lfcGxheWVyX2lkID09ICIwMC0wMDM2OTI0IiB8IGZhbnRhc3lfcGxheWVyX2lkID09ICIwMC0wMDM2Mjc1IiklPiUgCiAgICBmaWx0ZXIocnVzaF9hdHRlbXB0ID09IDEpICU+JSAKICBtdXRhdGUocnVzaGluZ195YXJkcyA9IHJlcGxhY2VfbmEocnVzaGluZ195YXJkcywgMCkpICU+JSAKICBncm91cF9ieShmYW50YXN5X3BsYXllcl9pZCwgZmFudGFzeV9wbGF5ZXJfbmFtZSkgJT4lIAogICBzdW1tYXJpc2UoVG90YWxSdXNoQXR0ZW1wdHMgPSBzdW0ocnVzaF9hdHRlbXB0KSwgVG90YWxSdXNoWWFyZHMgPSBzdW0ocnVzaGluZ195YXJkcyksIFlQQyA9IFRvdGFsUnVzaFlhcmRzL1RvdGFsUnVzaEF0dGVtcHRzLCBHYW1lc1BsYXllZCA9IG5fZGlzdGluY3QoZ2FtZV9pZCkpCmBgYApgYGB7cn0KTVlfUkJfT3ZlcmFsbCA8LSBNeVJCJT4lIAogIGlubmVyX2pvaW4oTXlSQl9yZWNlaXZpbmcsIGJ5PSAiZmFudGFzeV9wbGF5ZXJfbmFtZSIpCmBgYAoKI1F1ZXN0aW9uOgoKYGBge3J9CkV2ZXJ5V1I8LSBORkxSb3N0ZXJzICU+JSAKICBmaWx0ZXIocG9zaXRpb24gPT0gIldSIikgCmBgYAoKCmBgYHtyfQpFdmVyeVJCPC0gTkZMUm9zdGVycyAlPiUgCiAgZmlsdGVyKHBvc2l0aW9uID09ICJSQiIpIApgYGAKYGBge3J9CkFsbF9SQiA8LSBFdmVyeVJCICU+JSAKICBpbm5lcl9qb2luKE5GTCwgYnk9YygiZ3Npc19pZCIgPSAiZmFudGFzeV9wbGF5ZXJfaWQiKSkKYGBgCgpgYGB7cn0KQWxsX1JCIDwtIEFsbF9SQiAlPiUgCiAgICBncm91cF9ieShmdWxsX25hbWUsIGZhbnRhc3lfZGF0YV9pZCxwb3NpdGlvbixnc2lzX2lkKSAlPiUgCnN1bW1hcmlzZShUb3RhbFJ1c2hBdHRlbXB0cyA9IHN1bShydXNoX2F0dGVtcHQpLCBUb3RhbFJ1c2hZYXJkcyA9IHN1bShydXNoaW5nX3lhcmRzKSwgWVBDID0gVG90YWxSdXNoWWFyZHMvVG90YWxSdXNoQXR0ZW1wdHMpCmBgYAoKCmBgYHtyfQpFdmVyeVJCUmVjZWl2aW5nPC0gTkZMUm9zdGVycyAlPiUgCiAgZmlsdGVyKHBvc2l0aW9uID09ICJSQiIpIApgYGAKCmBgYHtyfQpBbGxfUkJfUmVjZWl2aW5nPC0gRXZlcnlSQlJlY2VpdmluZyAlPiUgCiAgaW5uZXJfam9pbihORkwsIGJ5PWMoImdzaXNfaWQiID0gImZhbnRhc3lfcGxheWVyX2lkIikpCmBgYAoKCmBgYHtyfQpFdmVyeVJCUmVjZWl2aW5nIDwtQWxsX1JCX1JlY2VpdmluZyAlPiUgCiAgICBncm91cF9ieShmdWxsX25hbWUsIGZhbnRhc3lfZGF0YV9pZCxwb3NpdGlvbikgJT4lIApzdW1tYXJpc2UoVG90YWxSZWNlaXZpbmdZZHMgPSBzdW0ocmVjZWl2aW5nX3lhcmRzKSwgQXZnX1JlY2VpdmluZ1lkcyA9IG1lYW4ocmVjZWl2aW5nX3lhcmRzKSwgVG90YWxfQWlyWWFyZHM9IHN1bShhaXJfeWFyZHMpLCBBdmdfQWlyWWFyZHM9IG1lYW4oYWlyX3lhcmRzKSwgQXZnX19ZQUMgPSBtZWFuICh5YXJkc19hZnRlcl9jYXRjaCksIFRvdGFsX1lBQyA9IHN1bSAoeWFyZHNfYWZ0ZXJfY2F0Y2gpLCBBdmdfQWlyRVBBID0gbWVhbiAoYWlyX2VwYSksIFRvdGFsX0FpckVQQSA9IHN1bShhaXJfZXBhKSwgQXZnX1lBQ0VQQSA9bWVhbiAoeWFjX2VwYSksIFRvdGFsX1lhY0VQQSA9IHN1bSh5YWNfZXBhKSwgQXZnX2NvbXBfYWlyX2VwYSA9IG1lYW4oY29tcF9haXJfZXBhKSwgVG90YWxfY29tcF9haXJfZXBhID0gc3VtIChjb21wX2Fpcl9lcGEpLCBUb3RhbF9ZQUNfQ29tcCA9IHN1bShjb21wX3lhY19lcGEpLCBBdmdfWUFDX0NvbXAgPSBtZWFuKGNvbXBfeWFjX2VwYSksIFRvdGFsX1lBQ19XUEEgPSBzdW0oeWFjX3dwYSksIEF2Z19ZQUNfV1BBID0gbWVhbih5YWNfd3BhKSwgVG90YWxFUEEgPSBzdW0oZXBhKSwgVG90YWxZYXJkc0dhaW5lZCA9IHN1bSh5YXJkc19nYWluZWQpLCBHYW1lc1BsYXllZCA9IG5fZGlzdGluY3QoZ2FtZV9pZCkpCmBgYAoKCgpgYGB7cn0KRXZlcnlURTwtIE5GTFJvc3RlcnMgJT4lIAogIGZpbHRlcihwb3NpdGlvbiA9PSAiVEUiKSAKYGBgCgpgYGB7cn0KQWxsX1RFIDwtIEV2ZXJ5VEUgJT4lIAogIGlubmVyX2pvaW4oTkZMLCBieT1jKCJnc2lzX2lkIiA9ICJmYW50YXN5X3BsYXllcl9pZCIpKQpgYGAKCgpgYGB7cn0KRXZlcnlRQjwtIE5GTFJvc3RlcnMgJT4lIAogIGZpbHRlcihwb3NpdGlvbiA9PSAiUUIiKSAKYGBgCmBgYHtyfQpBbGxfUUIgPC0gRXZlcnlRQiAlPiUgCiAgaW5uZXJfam9pbihORkwsIGJ5PWMoImdzaXNfaWQiID0gImZhbnRhc3lfcGxheWVyX2lkIikpCmBgYAoKYGBge3J9CkFsbF9RQiA8LSBBbGxfUUIgJT4lIAogICAgZ3JvdXBfYnkoZnVsbF9uYW1lLCBnc2lzX2lkLHBvc2l0aW9uKSAlPiUgCiAgc3VtbWFyaXNlIChBdmdfY29tcF9haXJfZXBhID0gbWVhbihjb21wX2Fpcl9lcGEpLCBUb3RhbF9jb21wX2Fpcl9lcGEgPSBzdW0gKGNvbXBfYWlyX2VwYSksIFRvdGFsX3Bhc3NfdG91Y2hkb3duID0gc3VtIChwYXNzX3RvdWNoZG93biksIFRvdGFsX2NvbXBsZXRlX3Bhc3MgPSBzdW0oY29tcGxldGVfcGFzcyksIFRvdGFsX1Bhc3NfYXR0ZW1wdCA9IHN1bShwYXNzX2F0dGVtcHQpLCBJbnRlcmNlcHRpb25zID0gc3VtKGludGVyY2VwdGlvbiksIFRvdGFsUUJFUEEgPXN1bShxYl9lcGEpLCBBdmdfUUJFUEEgPSBtZWFuKHFiX2VwYSksIEF2Z19wYXNzX29lID0gbWVhbihwYXNzX29lKSwgQXZnX2NvbXBfYWlyX2VwYSA9IG1lYW4oY29tcF9haXJfZXBhKSwgVG90YWxfY29tcF9haXJfZXBhID0gc3VtKGNvbXBfYWlyX2VwYSksIFRvdGFsRHJvcGJhY2tzPSBzdW0gKHFiX2Ryb3BiYWNrKSkKYGBgCgoKCmBgYHtyfQpBbGxfV1IgPC0gRXZlcnlXUiAlPiUgCiAgaW5uZXJfam9pbihORkwsIGJ5PWMoImdzaXNfaWQiID0gImZhbnRhc3lfcGxheWVyX2lkIikpCgpgYGAKYGBge3J9CkFsbF9XUiA8LSBBbGxfV1IgJT4lIAogIGdyb3VwX2J5KGZ1bGxfbmFtZSwgZmFudGFzeV9pZCxwb3NpdGlvbikgJT4lIAogIHJlbmFtZShmYW50YXN5X3BsYXllcl9pZCA9IGZhbnRhc3lfaWQpICU+JSAKICBzdW1tYXJpc2UoVG90YWxfQWlyWWFyZHM9IHN1bShhaXJfeWFyZHMpLCBBdmdfQWlyWWFyZHM9IG1lYW4oYWlyX3lhcmRzKSwgQXZnX19ZQUMgPSBtZWFuICh5YXJkc19hZnRlcl9jYXRjaCksIFRvdGFsX1lBQyA9IHN1bSAoeWFyZHNfYWZ0ZXJfY2F0Y2gpLCBBdmdfQWlyRVBBID0gbWVhbiAoYWlyX2VwYSksIFRvdGFsX0FpckVQQSA9IHN1bShhaXJfZXBhKSwgQXZnX1lBQ0VQQSA9bWVhbiAoeWFjX2VwYSksIFRvdGFsX1lhY0VQQSA9IHN1bSh5YWNfZXBhKSwgQXZnX2NvbXBfYWlyX2VwYSA9IG1lYW4oY29tcF9haXJfZXBhKSwgVG90YWxfY29tcF9haXJfZXBhID0gc3VtIChjb21wX2Fpcl9lcGEpLCBUb3RhbF9ZQUNfQ29tcCA9IHN1bShjb21wX3lhY19lcGEpLCBBdmdfWUFDX0NvbXAgPSBtZWFuKGNvbXBfeWFjX2VwYSksIFRvdGFsX1lBQ19XUEEgPSBzdW0oeWFjX3dwYSksIEF2Z19ZQUNfV1BBID0gbWVhbih5YWNfd3BhKSxUb3RhbFJlY2VpdmluZ1lkcyA9IHN1bShyZWNlaXZpbmdfeWFyZHMpLCBBdmdfUmVjZWl2aW5nWWRzID0gbWVhbihyZWNlaXZpbmdfeWFyZHMpLCBUb3RhbEVQQSA9IHN1bShlcGEpLCBUb3RhbEV4cGVjdGVkWUFDX0VQQSA9IHN1bSAoeHlhY19lcGEpLEF2Z0V4cGVjdGVkWUFDX0VQQSA9IG1lYW4gKHh5YWNfZXBhKSwgVG90YWxZYXJkc0dhaW5lZCA9IHN1bSh5YXJkc19nYWluZWQpKQpgYGAKCmBgYHtyfQpBbGxfV1IgPC1BbGxfV1IgJT4lIAogIGZpbHRlcihmdWxsX25hbWUgIT0gIkpvc2ggQWxpIikKYGBgCgpgYGB7cn0KZ2dwbG90KCkgKyBnZW9tX3BvaW50KGRhdGE9QWxsX1dSLCBhZXMoeD1BdmdfQWlyRVBBLCB5PUF2Z19ZQUNfQ29tcCkpCmBgYApgYGB7cn0KZ2dwbG90KCkgKyAKICBnZW9tX3BvaW50KGRhdGE9QWxsX1dSLCBhZXMoeD1BdmdfQWlyRVBBLCB5PUF2Z19jb21wX2Fpcl9lcGEpKSArCiAgZ2VvbV9zbW9vdGgoZGF0YT1BbGxfV1IsIGFlcyh4PUF2Z19BaXJFUEEsIHk9QXZnX2NvbXBfYWlyX2VwYSksIG1ldGhvZD0ibG0iKSArCiAgZ2VvbV9wb2ludChkYXRhPU15V1IsIGFlcyh4PUF2Z19BaXJFUEEsIHk9QXZnX2NvbXBfYWlyX2VwYSksIGNvbG9yPSJyZWQiKSArCiAgIGdlb21fdGV4dF9yZXBlbCgKICAgIGRhdGE9TXlXUiwKICAgIGFlcyh4PUF2Z19BaXJFUEEsIHk9QXZnX2NvbXBfYWlyX2VwYSwgbGFiZWw9ZmFudGFzeV9wbGF5ZXJfbmFtZSkpCgpgYGAKCgpgYGB7cn0KZ2dwbG90KCkgKyAKICBnZW9tX3BvaW50KGRhdGE9QWxsX1dSLCBhZXMoeD1Ub3RhbF9BaXJZYXJkcywgeT1Ub3RhbFJlY2VpdmluZ1lkcykpICsKICBnZW9tX3Ntb290aChkYXRhPUFsbF9XUiwgYWVzKHg9VG90YWxfQWlyWWFyZHMsIHk9VG90YWxSZWNlaXZpbmdZZHMpLCBtZXRob2Q9ImxtIikgKwogIGdlb21fcG9pbnQoZGF0YT1NeVdSLCBhZXMoeD1Ub3RhbF9BaXJZYXJkcywgeT1Ub3RhbFJlY2VpdmluZ1lkcyksIGNvbG9yPSJyZWQiKSArCmdlb21fdGV4dF9yZXBlbCgKICAgIGRhdGE9TXlXUiwKICAgIGFlcyh4PVRvdGFsX0FpcllhcmRzLCB5PVRvdGFsUmVjZWl2aW5nWWRzLCBsYWJlbD1mYW50YXN5X3BsYXllcl9uYW1lKSkKYGBgCmBgYHtyfQpnZ3Bsb3QoKSArIAogIGdlb21fcG9pbnQoZGF0YT1BbGxfV1IsIGFlcyh4PUF2Z19BaXJZYXJkcywgeT1BdmdfUmVjZWl2aW5nWWRzKSkgKwogIGdlb21fc21vb3RoKGRhdGE9QWxsX1dSLCBhZXMoeD1BdmdfQWlyWWFyZHMsIHk9QXZnX1JlY2VpdmluZ1lkcyksIG1ldGhvZD0ibG0iKSArCiAgZ2VvbV9wb2ludChkYXRhPU15V1IsIGFlcyh4PUF2Z19BaXJZYXJkcywgeT1BdmdfUmVjZWl2aW5nWWRzKSwgY29sb3I9InJlZCIpIAoKYGBgCgoKYGBge3J9CmdncGxvdCgpICsgCiAgZ2VvbV9wb2ludChkYXRhPUFsbF9SQiwgYWVzKHg9WVBDLCB5PVRvdGFsUnVzaEF0dGVtcHRzKSkgKwogIGdlb21fc21vb3RoKGRhdGE9QWxsX1JCLCBhZXMoeD1ZUEMsIHk9VG90YWxSdXNoQXR0ZW1wdHMpLCBtZXRob2Q9ImxtIikgKwogIGdlb21fcG9pbnQoZGF0YT1NeVJCLCBhZXMoeD1ZUEMsIHk9VG90YWxSdXNoQXR0ZW1wdHMpLCBjb2xvcj0icmVkIikgCgpgYGAKYGBge3J9CmdncGxvdCgpICsgCiAgZ2VvbV9wb2ludChkYXRhPUV2ZXJ5UkJSZWNlaXZpbmcsIGFlcyh4PUF2Z19BaXJFUEEsIHk9QXZnX1lBQ19Db21wKSkgKwogIGdlb21fc21vb3RoKGRhdGE9RXZlcnlSQlJlY2VpdmluZywgYWVzKHg9QXZnX0FpckVQQSwgeT1BdmdfWUFDX0NvbXApLCBtZXRob2Q9ImxtIikgKwogIGdlb21fcG9pbnQoZGF0YT1NeVJCX3JlY2VpdmluZywgYWVzKHg9QXZnX0FpckVQQSwgeT1BdmdfWUFDX0NvbXApLCBjb2xvcj0icmVkIikgCgpgYGAKCmBgYHtyfQpnZ3Bsb3QoKSArIAogIGdlb21fcG9pbnQoZGF0YT1BbGxfV1IsIGFlcyh4PVRvdGFsX0FpckVQQSwgeT1Ub3RhbEVQQSkpICsKICBnZW9tX3Ntb290aChkYXRhPUFsbF9XUiwgYWVzKHg9VG90YWxfQWlyRVBBLCB5PVRvdGFsRVBBKSwgbWV0aG9kPSJsbSIpICsKICBnZW9tX3BvaW50KGRhdGE9TXlXUiwgYWVzKHg9VG90YWxfQWlyRVBBLCB5PVRvdGFsRVBBKSwgY29sb3I9InJlZCIpIAoKYGBgCgoKCmBgYHtyfQpBSiA8LSBBbGxfV1IgJT4lIAogIGZpbHRlcihmdWxsX25hbWUgPT0gIkEuSi4gQnJvd24iKQpgYGAKYGBge3J9CkNoYXNlIDwtIEFsbF9XUiAlPiUgCiAgZmlsdGVyKGZ1bGxfbmFtZSA9PSAiSmEnTWFyciBDaGFzZSIpCmBgYAoKCkphJ01hcnIgQ2hhc2UKCmBgYHtyfQpnZ3Bsb3QoKSArIAogIGdlb21fcG9pbnQoZGF0YT1BbGxfV1IsIGFlcyh4PUF2Z19BaXJZYXJkcywgeT1BdmdfUmVjZWl2aW5nWWRzKSkgKwogIGdlb21fc21vb3RoKGRhdGE9QWxsX1dSLCBhZXMoeD1BdmdfQWlyWWFyZHMsIHk9QXZnX1JlY2VpdmluZ1lkcyksIG1ldGhvZD0ibG0iKSArCiAgZ2VvbV9wb2ludChkYXRhPUFKLCBhZXMoeD1BdmdfQWlyWWFyZHMsIHk9QXZnX1JlY2VpdmluZ1lkcyksIGNvbG9yPSJyZWQiKSAKCmBgYAoKYGBge3J9CmdncGxvdCgpICsgCiAgZ2VvbV9wb2ludChkYXRhPUFsbF9XUiwgYWVzKHg9QXZnX0FpcllhcmRzLCB5PUF2Z19SZWNlaXZpbmdZZHMpKSArCiAgZ2VvbV9zbW9vdGgoZGF0YT1BbGxfV1IsIGFlcyh4PUF2Z19BaXJZYXJkcywgeT1BdmdfUmVjZWl2aW5nWWRzKSwgbWV0aG9kPSJsbSIpICsKICBnZW9tX3BvaW50KGRhdGE9Q2hhc2UsIGFlcyh4PUF2Z19BaXJZYXJkcywgeT1BdmdfUmVjZWl2aW5nWWRzKSwgY29sb3I9InJlZCIpIAoKYGBgCgpKdXN0aW4gSmVmZmVyc29uCgpgYGB7cn0KSmV0dHMgPC0gQWxsX1dSICU+JSAKICBmaWx0ZXIoZnVsbF9uYW1lID09ICJKdXN0aW4gSmVmZmVyc29uIikKYGBgCgoKYGBge3J9CmdncGxvdCgpICsgCiAgZ2VvbV9wb2ludChkYXRhPUFsbF9XUiwgYWVzKHg9QXZnX0FpcllhcmRzLCB5PUF2Z19SZWNlaXZpbmdZZHMpKSArCiAgZ2VvbV9zbW9vdGgoZGF0YT1BbGxfV1IsIGFlcyh4PUF2Z19BaXJZYXJkcywgeT1BdmdfUmVjZWl2aW5nWWRzKSwgbWV0aG9kPSJsbSIpICsKICBnZW9tX3BvaW50KGRhdGE9SmV0dHMsIGFlcyh4PUF2Z19BaXJZYXJkcywgeT1BdmdfUmVjZWl2aW5nWWRzKSwgY29sb3I9InJlZCIpIAoKYGBgCmBgYHtyfQpHYWJlIDwtIEFsbF9XUiAlPiUgCiAgZmlsdGVyKGZ1bGxfbmFtZSA9PSAiR2FiZSBEYXZpcyIpCmBgYApHYWJlIERhdmlzCmBgYHtyfQpnZ3Bsb3QoKSArIAogIGdlb21fcG9pbnQoZGF0YT1BbGxfV1IsIGFlcyh4PUF2Z19BaXJZYXJkcywgeT1BdmdfUmVjZWl2aW5nWWRzKSkgKwogIGdlb21fc21vb3RoKGRhdGE9QWxsX1dSLCBhZXMoeD1BdmdfQWlyWWFyZHMsIHk9QXZnX1JlY2VpdmluZ1lkcyksIG1ldGhvZD0ibG0iKSArCiAgZ2VvbV9wb2ludChkYXRhPUdhYmUsIGFlcyh4PUF2Z19BaXJZYXJkcywgeT1BdmdfUmVjZWl2aW5nWWRzKSwgY29sb3I9InJlZCIpIAoKYGBgCmBgYHtyfQpnZ3Bsb3QoKSArIAogIGdlb21fcG9pbnQoZGF0YT1BbGxfV1IsIGFlcyh4PUF2Z19ZQUNFUEEsIHk9QXZnX0FpckVQQSkpICsKICBnZW9tX3Ntb290aChkYXRhPUFsbF9XUiwgYWVzKHg9QXZnX1lBQ0VQQSwgeT1BdmdfQWlyRVBBKSwgbWV0aG9kPSJsbSIpICsKICBnZW9tX3BvaW50KGRhdGE9Q2hhc2UsIGFlcyh4PUF2Z19ZQUNFUEEsIHk9QXZnX0FpckVQQSksIGNvbG9yPSJyZWQiKSAKCmBgYAoKYGBge3J9CkpldWR5IDwtIEFsbF9XUiAlPiUgCiAgZmlsdGVyKGZ1bGxfbmFtZSA9PSAiSmVycnkgSmV1ZHkiKQpgYGAKCgoKCmBgYHtyfQpXUkVQQTwtIEFsbF9XUiAlPiUgCiAgZ3JvdXBfYnkoZnVsbF9uYW1lKSAlPiUgCiAgc3VtbWFyaXNlKFRvdGFsRVBBLCBUb3RhbF9BaXJFUEEsIFRvdGFsRXhwZWN0ZWRZQUNfRVBBLCBBdmdFeHBlY3RlZFlBQ19FUEEsIFRvdGFsUmVjZWl2aW5nWWRzKQpgYGAKCmBgYHtyfQpNeV9XUl9UYXJnZXRzIDwtIE5GTCAlPiUKICBmaWx0ZXIoIWlzLm5hKHJlY2VpdmVyX3BsYXllcl9uYW1lKSkgJT4lIAogIGdyb3VwX2J5KHJlY2VpdmVyX3BsYXllcl9pZCwgcmVjZWl2ZXJfcGxheWVyX25hbWUsIGNvbXBsZXRlX3Bhc3MpICU+JSAKICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gY29tcGxldGVfcGFzcywgdmFsdWVzX2Zyb20gPSBjb3VudCkgJT4lIAogIHJlbmFtZShyZWNlcHRpb25zID0gYDFgLCBpbmNvbXBsZXRpb25zID0gYDBgKSAlPiUgCiAgbXV0YXRlKHJlY2VwdGlvbnMgPSByZXBsYWNlX25hKHJlY2VwdGlvbnMsIDApLCBpbmNvbXBsZXRpb25zID0gcmVwbGFjZV9uYShpbmNvbXBsZXRpb25zLCAwKSkgJT4lIAogIG11dGF0ZSh0YXJnZXRzID0gcmVjZXB0aW9ucyArIGluY29tcGxldGlvbnMpICU+JSAKICBpbm5lcl9qb2luKE15V1IsIGJ5PWMoInJlY2VpdmVyX3BsYXllcl9pZCI9ImZhbnRhc3lfcGxheWVyX2lkIikpCmBgYApgYGB7cn0KTXlfV1JfVGFyZ2V0c19QRyA8LSBNeV9XUl9UYXJnZXRzICU+JSAKICBzdW1tYXJpc2UoIFRhcmdldHNQZWdHYW1lID0gdGFyZ2V0cy9HYW1lc1BsYXllZCkKICAKYGBgCgpgYGB7cn0KV1JfVGFyZ2V0cyA8LSBORkwgJT4lCiAgZmlsdGVyKCFpcy5uYShyZWNlaXZlcl9wbGF5ZXJfbmFtZSkpICU+JSAKICBncm91cF9ieShyZWNlaXZlcl9wbGF5ZXJfaWQsIHJlY2VpdmVyX3BsYXllcl9uYW1lLCBjb21wbGV0ZV9wYXNzKSAlPiUgCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpLCBHYW1lc1BsYXllZCA9IG5fZGlzdGluY3QoZ2FtZV9pZCkpICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gY29tcGxldGVfcGFzcywgdmFsdWVzX2Zyb20gPSBjb3VudCkgJT4lIAogIHJlbmFtZShyZWNlcHRpb25zID0gYDFgLCBpbmNvbXBsZXRpb25zID0gYDBgKSAlPiUgCiAgbXV0YXRlKHJlY2VwdGlvbnMgPSByZXBsYWNlX25hKHJlY2VwdGlvbnMsIDApLCBpbmNvbXBsZXRpb25zID0gcmVwbGFjZV9uYShpbmNvbXBsZXRpb25zLCAwKSkgJT4lIAogIG11dGF0ZSh0YXJnZXRzID0gcmVjZXB0aW9ucyArIGluY29tcGxldGlvbnMpICU+JSAKICBpbm5lcl9qb2luKEFsbF9XUiwgYnk9YygicmVjZWl2ZXJfcGxheWVyX2lkIj0iZmFudGFzeV9wbGF5ZXJfaWQiKSkKYGBgCmBgYHtyfQpXUl9UYXJnZXRzX1BHIDwtIFdSX1RhcmdldHMgJT4lIAogIHN1bW1hcmlzZSggVGFyZ2V0c1BlZ0dhbWUgPSB0YXJnZXRzL0dhbWVzUGxheWVkKQpgYGAKCgpgYGB7cn0KZ2dwbG90KCkgKyAKICBnZW9tX3BvaW50KGRhdGE9V1JfVGFyZ2V0cywgYWVzKHg9dGFyZ2V0cywgeT1Ub3RhbEVQQSkpICsKICBnZW9tX3Ntb290aChkYXRhPVdSX1RhcmdldHMsIGFlcyh4PXRhcmdldHMsIHk9VG90YWxFUEEpLCBtZXRob2Q9ImxtIikgKwogIGdlb21fcG9pbnQoZGF0YT1NeV9XUl9UYXJnZXRzLCBhZXMoeD10YXJnZXRzLCB5PVRvdGFsRVBBKSwgY29sb3I9InJlZCIpICsKZ2VvbV90ZXh0X3JlcGVsKAogICAgZGF0YT1NeV9XUl9UYXJnZXRzLAogICAgYWVzKHg9dGFyZ2V0cywgeT1Ub3RhbEVQQSwgbGFiZWw9ZmFudGFzeV9wbGF5ZXJfbmFtZSkpCmBgYAoKYGBge3J9CkFsbF9URSA8LSBBbGxfVEUgJT4lIAogICAgZ3JvdXBfYnkoZnVsbF9uYW1lLCBmYW50YXN5X2RhdGFfaWQscG9zaXRpb24pICU+JQogIHN1bW1hcmlzZShUb3RhbF9BaXJZYXJkcz0gc3VtKGFpcl95YXJkcyksIEF2Z19BaXJZYXJkcz0gbWVhbihhaXJfeWFyZHMpLCBBdmdfX1lBQyA9IG1lYW4gKHlhcmRzX2FmdGVyX2NhdGNoKSwgVG90YWxfWUFDID0gc3VtICh5YXJkc19hZnRlcl9jYXRjaCksIEF2Z19BaXJFUEEgPSBtZWFuIChhaXJfZXBhKSwgVG90YWxfQWlyRVBBID0gc3VtKGFpcl9lcGEpLCBBdmdfWUFDRVBBID1tZWFuICh5YWNfZXBhKSwgVG90YWxfWWFjRVBBID0gc3VtKHlhY19lcGEpLCBBdmdfY29tcF9haXJfZXBhID0gbWVhbihjb21wX2Fpcl9lcGEpLCBUb3RhbF9jb21wX2Fpcl9lcGEgPSBzdW0gKGNvbXBfYWlyX2VwYSksIFRvdGFsX1lBQ19Db21wID0gc3VtKGNvbXBfeWFjX2VwYSksIEF2Z19ZQUNfQ29tcCA9IG1lYW4oY29tcF95YWNfZXBhKSwgVG90YWxfWUFDX1dQQSA9IHN1bSh5YWNfd3BhKSwgQXZnX1lBQ19XUEEgPSBtZWFuKHlhY193cGEpLFRvdGFsUmVjZWl2aW5nWWRzID0gc3VtKHJlY2VpdmluZ195YXJkcyksIEF2Z19SZWNlaXZpbmdZZHMgPSBtZWFuKHJlY2VpdmluZ195YXJkcykpCmBgYAoKYGBge3J9ClJCX1J1c2hlczwtIE5GTCAlPiUKICBmaWx0ZXIoIWlzLm5hKHJ1c2hlcl9wbGF5ZXJfbmFtZSkpICU+JSAKICBncm91cF9ieShydXNoZXJfcGxheWVyX2lkLCBydXNoZXJfcGxheWVyX25hbWUpICU+JSAKICBzdW1tYXJpc2UoY291bnQgPSBuKCkpIApgYGAKYGBge3J9CkFMTF9XUl9GUCA8LSBBbGxfV1IgJT4lIAogIGlubmVyX2pvaW4oV1JfNTUsIGJ5PWMoImZhbnRhc3lfcGxheWVyX2lkIikpIApgYGAKYGBge3J9CiBBTExfV1JfRlAgPC0gQUxMX1dSX0ZQICU+JSAKICAgZmlsdGVyKGZ1bGxfbmFtZSAhPSAiRW1la2EgRW1lemllIikgCmBgYAoKCmBgYHtyfQpBTExfUkJfRlAgPC0gQWxsX1JCICU+JSAKICBpbm5lcl9qb2luKFJCXzU1LCBieT1jKCJnc2lzX2lkIj0iZmFudGFzeV9wbGF5ZXJfaWQiKSkKYGBgCgpgYGB7cn0KQUxMX1FCX0ZQIDwtIEFsbF9RQiAlPiUgCiAgaW5uZXJfam9pbihRQjI0LCBieT1jKCJnc2lzX2lkIj0iZmFudGFzeV9wbGF5ZXJfaWQiKSkKYGBgCgpgYGB7cn0KQUxMX1RFX0ZQIDwtIEV2ZXJ5VEUgJT4lIAogIGlubmVyX2pvaW4oVEVfMjQsIGJ5PWMoImdzaXNfaWQiPSJmYW50YXN5X3BsYXllcl9pZCIpKQpgYGAKCgoKCgpgYGB7cn0KQUxMX1dSX0ZQMTAgPC0gQWxsX1dSICU+JSAKICBpbm5lcl9qb2luKFdSXzU1LCBieT1jKCJmYW50YXN5X3BsYXllcl9pZCIpKSAlPiUgCiAgZmlsdGVyKGZ1bGxfbmFtZSAhPSAiRW1la2EgRW1lemllIikgJT4lIAogIGFycmFuZ2UoZGVzYyhgRlBUUy9HYCkpICU+JSAKICBoZWFkKDEwKQpgYGAKCgoKYGBge3J9CkFMTF9SQl9GUDEwPC0gQWxsX1JCICU+JSAKICBpbm5lcl9qb2luKFJCXzU1LCBieT1jKCJnc2lzX2lkIj0iZmFudGFzeV9wbGF5ZXJfaWQiKSkgJT4lIAogIGFycmFuZ2UoZGVzYyhgRlBUUy9HYCkpICU+JSAKICBoZWFkKDEwKQpgYGAKCmBgYHtyfQpBTExfUUJfRlAxMCA8LSBBbGxfUUIgJT4lIAogIGlubmVyX2pvaW4oUUIyNCwgYnk9YygiZ3Npc19pZCI9ImZhbnRhc3lfcGxheWVyX2lkIikpICU+JSAKICBhcnJhbmdlKGRlc2MoYEZQVFMvR2ApKSAlPiUgCiAgaGVhZCgxMCkKYGBgCgpgYGB7cn0KQUxMX1RFX0ZQMTAgPC0gRXZlcnlURSAlPiUgCiAgaW5uZXJfam9pbihURV8yNCwgYnk9YygiZ3Npc19pZCI9ImZhbnRhc3lfcGxheWVyX2lkIikpICU+JSAKICAgIGFycmFuZ2UoZGVzYyhgRlBUUy9HYCkpICU+JSAKICBoZWFkKDEwKQpgYGAKIAojUXVhcmV0YmFjayBBbmFseXNpcwpNeSBpbml0aWFsIGh1bmNoIHdhcyB0aGF0IHJ1c2hpbmcgaXMgYSBtYWpvciBmYWN0b3IgaW4gZGV0ZXJtaW5pbmcgdGhlIHZhbHVlIGZhbnRhc3kgc3VjY2VzcyBieSBxdWFydGVyYmFja3MuCmBgYHtyfQpnZ3Bsb3QoKSArIAogIGdlb21faml0dGVyKAogICAgZGF0YT1BTExfUUJfRlAsIAogICAgYWVzKHg9YEZQVFMvR2AsIHk9Ul9BVFQpLCBjb2xvcj0iZ3JleSIpICArCiAgZ2VvbV90ZXh0X3JlcGVsKAogICAgZGF0YT1BTExfUUJfRlAsIAogICAgYWVzKHg9YEZQVFMvR2AsIHk9Ul9BVFQsIGxhYmVsPWZ1bGxfbmFtZSkpICsKICBnZW9tX2ppdHRlcigKICAgIGRhdGE9QUxMX1FCX0ZQMTAsIAogICAgZ3JvdXBPblg9VFJVRSwgCiAgICBhZXMoeD1gRlBUUy9HYCwgeT1SX0FUVCksIGNvbG9yPSJyZWQiKSArCiAgbGFicyh4PSJGYW50YXN5IFBvaW50cyBQZXIgR2FtZSIsIHk9IlJ1c2hpbmcgQXR0ZW1wdHMiLCB0aXRsZT0iQ29ycmVsYXRpb24gQmV0d2VlbiBSdXNoZXMgYW5kIEZhbnRhc3kgUG9pbnRzIFBlciBHYW1lIGJ5IFFCcyIsIHN1YnRpdGxlPSIqKkRhdGEgdGhyb3VnaCBXZWVrIDExKioiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAojTm90ZQpUaGlzIGZpcnN0IGdyYXBoIGNvbmZpcm1lZCBteSBpbml0aWFsIGh5cG90aGVzaXMgdGhhdCB0aGVyZSBpcyBhIHNpZ25pZmljYW50IGNvcnJlbGF0aW9uIGJldHdlZW4gcnVzaGluZyBhdHRlbXB0cyBhbmQgZmFudGFzeSBwb2ludHMgc2NvcmVkLiBIb3dldmVyLCBpbiB0aGUgbmV4dCBncmFwaHMsIEkgaGFkIHRvIGNoYXJ0IHNvbWUgcGFzc2luZyBzdGF0cyBpbiBvcmRlciB0byBkZXRlcm1pbmUgaXRzIGFjY3VyYXJ5LiAKYGBge3J9CmdncGxvdCgpICsgCiAgZ2VvbV9qaXR0ZXIoCiAgICBkYXRhPUFMTF9RQl9GUCwgCiAgICBhZXMoeD1gRlBUUy9HYCwgeT1Ub3RhbERyb3BiYWNrcyksIGNvbG9yPSJncmV5IikgICsKICBnZW9tX3RleHRfcmVwZWwoCiAgICBkYXRhPUFMTF9RQl9GUCwgCiAgICBhZXMoeD1gRlBUUy9HYCwgeT1Ub3RhbERyb3BiYWNrcywgbGFiZWw9ZnVsbF9uYW1lKSkgKwogIGdlb21faml0dGVyKAogICAgZGF0YT1BTExfUUJfRlAxMCwgCiAgICBncm91cE9uWD1UUlVFLCAKICAgIGFlcyh4PWBGUFRTL0dgLCB5PVRvdGFsRHJvcGJhY2tzKSwgY29sb3I9InJlZCIpICsKICBsYWJzKHg9IkZhbnRhc3kgUG9pbnRzIFBlciBHYW1lIiwgeT0iRHJvcGJhY2tzIiwgdGl0bGU9IkNvcnJlbGF0aW9uIEJldHdlZW4gRHJvcGJhY2tzIGFuZCBGYW50YXN5IFBvaW50cyBQZXIgR2FtZSBieSBRQnMiLCBzdWJ0aXRsZT0iKipEYXRhIHRocm91Z2ggV2VlayAxMSoqIikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKI05vdGUKQmFzZWQgb24gdGhpcyBjaGFydCwgaXQgYmVjb21lcyBjbGVhciB0aGF0IGRyb3AgYmFja3MgZGlyZWN0bHkgY29ycmVsYXRlcyB0byBmYW50YXN5IHBvaW50cyB3aGljaCBzZWVtcyBvYnZpb3VzLiBUaGUgbW9yZSBjaGFuY2VzIHlvdSBoYXZlIHRvIG1ha2UgYSBwbGF5LCB0aGUgbW9yZSBwb2ludHMgeW91IGFyZSBsaWtlbHkgdG8gdGFsbHkuCmBgYHtyfQpnZ3Bsb3QoKSArIAogIGdlb21faml0dGVyKAogICAgZGF0YT1BTExfUUJfRlAsIAogICAgYWVzKHg9YEZQVFMvR2AsIHk9QXZnX1FCRVBBKSwgY29sb3I9ImdyZXkiKSAgKwogIGdlb21fdGV4dF9yZXBlbCgKICAgIGRhdGE9QUxMX1FCX0ZQLCAKICAgIGFlcyh4PWBGUFRTL0dgLCB5PUF2Z19RQkVQQSwgbGFiZWw9ZnVsbF9uYW1lKSkgKwogIGdlb21faml0dGVyKAogICAgZGF0YT1BTExfUUJfRlAxMCwgCiAgICBncm91cE9uWD1UUlVFLCAKICAgIGFlcyh4PWBGUFRTL0dgLCB5PUF2Z19RQkVQQSksIGNvbG9yPSJyZWQiKSArCiAgbGFicyh4PSJGYW50YXN5IFBvaW50cyBQZXIgR2FtZSIsIHk9IkF2ZXJhZ2UgUUIgRVBBIiwgdGl0bGU9IkNvcnJlbGF0aW9uIEJldHdlZW4gQXZlcmFnZSBRQiBFUEEgYW5kIEZhbnRhc3kgUG9pbnRzIFBlciBHYW1lIGJ5IFFCcyIsIHN1YnRpdGxlPSIqKkRhdGEgdGhyb3VnaCBXZWVrIDExKioiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAojTm90ZSAKRVBBIGlzIGRlZmluZWQgYXMgZXhwZWN0ZWQgcG9pbnRzIGFkZGVkLiBJbiB0aGlzIGNhc2UgUUIgRVBBLCByZWZlcnMgdG8gcG9pbnRzIGFkZGVkIGJ5IGEgUUIgd2l0aCBlaXRoZXIgdGhlaXIgYXJtcyBvciBsZWdzIGFuZCB0YWtlcyBpbnRvIGFjY291bnQgeWFyZHMgcGVyIGF0dGVtcHQsIHlhcmRzIHBlciBydXNoLCBZQUMsIEVUQyB0byBhY2N1cmF0ZWx5IGZvY3VzIHNvbGV5IG9uIHRoZSBRQi4gVHVhIHJhbmtzIGxvd2VyIGluIHRoaXMgbWV0cmljIGJlY2F1c2UgaGUgaXMgb2Z0ZW4gYmVuZWZpdGVkIGJ5IHNob3J0IHBhc3NlcyB0dXJuaW5nIGludG8gZXhwbG9zaXZlIHBsYXlzIGJlY2F1c2Ugb2YgZWxpdGUgcGxheW1ha2VyLCBhcyBpcyBKaW1teSBHLiAKCgpgYGB7cn0KZ2dwbG90KCkgKyAKICBnZW9tX2ppdHRlcigKICAgIGRhdGE9QUxMX1FCX0ZQLCAKICAgIGFlcyh4PWBGUFRTL0dgLCB5PUFUVCksIGNvbG9yPSJncmV5IikgICsKICBnZW9tX3RleHRfcmVwZWwoCiAgICBkYXRhPUFMTF9RQl9GUCwgCiAgICBhZXMoeD1gRlBUUy9HYCwgeT1BVFQsIGxhYmVsPWZ1bGxfbmFtZSkpICsKICBnZW9tX2ppdHRlcigKICAgIGRhdGE9QUxMX1FCX0ZQMTAsIAogICAgZ3JvdXBPblg9VFJVRSwgCiAgICBhZXMoeD1gRlBUUy9HYCwgeT1BVFQpLCBjb2xvcj0icmVkIikgKwogIGxhYnMoeD0iRmFudGFzeSBQb2ludHMgUGVyIEdhbWUiLCB5PSJBdHRlbXB0cyIsIHRpdGxlPSJDb3JyZWxhdGlvbiBCZXR3ZWVuIFBhc3NpbmcgQXR0ZW1wdHMgYW5kIEZhbnRhc3kgUG9pbnRzIFBlciBHYW1lIGJ5IFFCcyIsIHN1YnRpdGxlPSIqKkRhdGEgdGhyb3VnaCBXZWVrIDExKioiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAojTm90ZQpCYXNlZCBvbiB0aGlzIGRhdGEsIHRoZXJlIGlzIG5vIHJlYWwgY29ycmVsYXRpb24gYmV0d2VlbiBwYXNzZXMgdGhyb3duIGFuZCBmYW50YXN5IHJlbGV2YW5jZSB0aGlzIHNlYXNvbi4gTWFob21lcywgQnVycm93IGFuZCBBbGxlbiBhcmUgb3V0bGllcnMsIGVzcGVjaWFsbHkgY29uc2lkZXJpbmcgdGhlIHBhc3Mgdm9sdW1lIG9mIGJvdGggQnVmZmFsbydzIGFuZCBLYW5zYXMgQ2l0eSdzIG9mZmVuc2VzLgoKYGBge3J9CmdncGxvdCgpICsgCiAgZ2VvbV9qaXR0ZXIoCiAgICBkYXRhPUFMTF9RQl9GUCwgCiAgICBhZXMoeD1gRlBUUy9HYCwgeT1SX1lEUyksIGNvbG9yPSJncmV5IikgICsKICBnZW9tX3RleHRfcmVwZWwoCiAgICBkYXRhPUFMTF9RQl9GUCwgCiAgICBhZXMoeD1gRlBUUy9HYCwgeT1SX1lEUywgbGFiZWw9ZnVsbF9uYW1lKSkgKwogIGdlb21faml0dGVyKAogICAgZGF0YT1BTExfUUJfRlAxMCwgCiAgICBncm91cE9uWD1UUlVFLCAKICAgIGFlcyh4PWBGUFRTL0dgLCB5PVJfWURTKSwgY29sb3I9InJlZCIpICsKICBsYWJzKHg9IkZhbnRhc3kgUG9pbnRzIFBlciBHYW1lIiwgeT0iUnVzaGluZyBZYXJkcyIsIHRpdGxlPSJDb3JyZWxhdGlvbiBCZXR3ZWVuIFJ1c2hpbmcgWWFyZHMgYW5kIEZhbnRhc3kgUG9pbnRzIFBlciBHYW1lIGJ5IFFCcyIsIHN1YnRpdGxlPSIqKkRhdGEgdGhyb3VnaCBXZWVrIDExKioiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKI0NvbmNsdXNpb24gZm9yIFFCCkJhc2VkIG9uIHRoZSBmb3VyIHByaW9yIGNoYXJ0cyBhbmQgc2lmdGluZyB0aHJvdWdoIG90aGVyIHBvc3NpYmxlIGNvcnJlbGF0aW9ucyAsIEkgYmVsaWV2ZSB0aGF0IHJ1c2hpbmcgaXMgdGhlIHByaW1hcnkgZGV0ZXJtaW5hbnQgb2Ygc3VjY2VzcyBhdCB0aGUgUUIgcG9zaXRpb24sIGNvbmZpcm1pbmcgbXkgaHlwb3RoZXNpcy4gV2hhdCBzcGVjaWZpY2FsbHkgY2xhcmlmaWVkIHRoaXMgY29uY2VwdCB0byBtZSB3YXMgdGhlIGRpZmZlcmVudGlhdGlvbiBiZXR3ZWVuIGF0dGVtcHRzIGFuZCBkcm9wYmFja3MuCgpBdHRlbXB0cyByZWZlcnMgdG8gdGhlIGFtb3VudCBvZiBwYXNzZXMgdGhyb3duIHZlcnN1cyBkcm9wIGJhY2tzIHdoaWNoIHNpZ25pZnkgdGhlIGFtb3VudCBvZiB0aW1lcyB0aGV5IGRyb3BwZWQgYmFjayB0byBwYXNzLiBUaGlzIGlzIGJlY2F1c2UgZHJvcGJhY2tzLCBlc3BlY2lhbGx5IGZvciBtb2JpbGUgcXVhcnRlcmJhY2tzLCBhbGxvdyB0aGUgb3Bwb3J0dW5pdHkgZm9yIHNjcmFtYmxpbmcuIEluIGZhbnRhc3kgZm9vdGJhbGwsIFFCcyByZWNpZXZlIC4xIHBvaW50IHBlciB5YXJkIHJ1c2hlZCwgYXMgY29tcGFyZWQgdG8gLjA0IHBvaW50cyBmb3IgZXZlcnkgcGFzc2luZyB5YXJkLiBGb3IgcGFzc2luZyB0b3VjaGRvd25zLCBRQnMgcmVjaWV2ZSA0IHBvaW50cyBhcyBjb21wYXJlZCB0byA2IHBvaW50cyBmb3IgcnVzaGluZyB0b3VjaGRvd25zLiAKCkp1c3RpbiBGaWVsZHMgaXMgYSBwcmltZSBleGFtcGxlLiBBcm91bmQgdGhlIE5GTCwgRmllbGRzIGlzIGtub3duIGZvciBoaXMgZWxpdGUgcnVzaGluZyBidXQgaGFzIHN0cnVnZ2xlZCB0aHJvd2luZyB0aGUgZm9vdGJhbGwgZWFybHkgaW4gaGlzIGNhcmVlci4gSG93ZXZlciwgZGVzcGl0ZSBzdWIgcGFyIHRocm93aW5nIG51bWJlcnMsIHRoZSAybmQgeWVhciBRQiBoYXMgZW1lcmdlZCBhcyBhbiBlbGl0ZSBmYW50YXN5IFFCIG9wdGlvbiBwcmltYXJpbHkgYmVjYXVzZSBvZiBoaXMgbGVncy4gRGFuaWVsIEpvbmVzIGlzIGFsc28gbm90IGtub3duIGFzIGFuIGVsaXRlIHRocm93ZXIsIGJ1dCBoaXMgdmVyc2F0aWxpdHkgYW5kIHZvbHVtZSBpbiB0aGUgcnVuIGdhbWUgbWFrZSBoaW0gYSB2ZXJ5IHZpYWJsZS4gCgpPdmVyYWxsLCBpdCBpcyBjbGVhciB0aGF0IHRoZSBkYXlzIG9mIHBpY2tpbmcgYSBRQiB3aG8gZG9lcyBub3QgcmVhbGx5IHVzZSBoaXMgbGVncyBhcmUgYmVoaW5kIHVzIGluIGZhbnRhc3kgZm9vdGJhbGwuIEdyYWJiaW5nIGFuIGVsaXRlIHJ1c2hpbmcgcXVhcnRlcmJhY2sgb2Z0ZW4gbWVhbnMgZ3JhYmJpbmcgYSBhIHByZXR0eSBnb29kIGZhbnRhc3kgcXVhcnRlcmJhY2suIEJ5IGFkZGluZyB0b3AgdGllciB0aHJvd2luZyB3aXRoIGEgZ29vZCBtaXggb2YgcnVubmluZywgeW91IHZlbnR1cmUgaW50byBlbGl0ZSBxdWFydGVyYmFjayByYW5nZS4gVGhlcmUgYXJlIHZpYWJsZSBzdGFydGluZyBvcHRpb25zIG9uIGJvdGggdGhlIHJ1bm5pbmcgYW5kIHBhc3Npbmcgc2lkZSBvZiB0aGUgc3BlY3RydW0uIEhvd2V2ZXIsIGlmIHlvdSB3YW50IGFuIGVsaXRlIFFCLCB5b3UgbmVlZCBhIHN0cm9uZyBkb3NhZ2Ugb2YgcnVubmluZy4KCiNUaWdodCBFbmRzCkZvciB0aWdodCBlbmRzIGluIGZhbnRhc3kgZm9vdGJhbGwsIGl0J3MgZWl0aGVyIHlvdSBoYXZlIGFuIG9idmlvdXNseSBnb29kIHBsYXllciBvciB5b3UncmUgcm9sbGluZyB0aGUgZGljZSBpbiAyMDIyLiBFc3BlY2lhbGx5IGF0IHRpZ2h0IGVuZCwgd2hlcmUgZWZmaWNpZW5jeSBpcyB0aGUgbmFtZSBvZiB0aGUgZ2FtZSBkdWUgdG8gbGVzc2VyIHZvbHVtZSwgZXhwbG9zaXZlIHBsYXlzIGFuZCB0b3VjaGR3b25zIGFyZSB0eXBpY2FsbHkgdGhlIG1haW4gZHRlcm1pbmVudCBvZiBzdWNjZXNzLiAKYGBge3J9CmdncGxvdCgpICsgCiAgZ2VvbV9qaXR0ZXIoCiAgICBkYXRhPUFMTF9URV9GUCwgCiAgICBhZXMoeD1gRlBUUy9HYCwgeT1gWS9SYCksIGNvbG9yPSJncmV5IikgICsKICBnZW9tX3RleHRfcmVwZWwoCiAgICBkYXRhPUFMTF9URV9GUCwgCiAgICBhZXMoeD1gRlBUUy9HYCwgeT1gWS9SYCwgbGFiZWw9ZnVsbF9uYW1lKSkgKwogIGdlb21faml0dGVyKAogICAgZGF0YT1BTExfVEVfRlAxMCwgCiAgICBncm91cE9uWD1UUlVFLCAKICAgIGFlcyh4PWBGUFRTL0dgLCB5PWBZL1JgKSwgY29sb3I9InJlZCIpICsKICBsYWJzKHg9IkZhbnRhc3kgUG9pbnRzIFBlciBHYW1lIiwgeT0iWWFyZHMgcGVyIFJlY2VwdGlvbiIsIHRpdGxlPSJDb3JyZWxhdGlvbiBCZXR3ZWVuIFlhcmRzIHBlciBSZWNlcHRpb25zIGFuZCBGYW50YXN5IFBvaW50cyBQZXIgR2FtZSBieSBUaWdodCBFbmRzIiwgc3VidGl0bGU9IioqRGF0YSB0aHJvdWdoIFdlZWsgMTEqKiIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCiNOb3RlClRoaXMgZGF0YSBzdXBwb3J0cyB0aGlzIGlkZWEuIEFsbCBvZiB0aGVzZSB0aWdodCBlbmRzIGFyZSBvZnRlbiB1c2VkIHZlcnRpY2FsbHkgZG93biB0aGUgZmllbGQgYW5kIGFyZSBleHRyZW1lbHkgZ29vZCBhdCBydW5uaW5nIGFmdGVyIHRoZSBjYXRjaCwgbWVhbmluZyB0aGV5IGNhcGl0YWxpemUgb24gdGhlaXIgb3Bwb3J0dW5pdGllcy4gCgpgYGB7cn0KZ2dwbG90KCkgKyAKICBnZW9tX2ppdHRlcigKICAgIGRhdGE9QUxMX1RFX0ZQLCAKICAgIGFlcyh4PWBGUFRTL0dgLCB5PWAyMCtgKSwgY29sb3I9ImdyZXkiKSAgKwogIGdlb21fdGV4dF9yZXBlbCgKICAgIGRhdGE9QUxMX1RFX0ZQLCAKICAgIGFlcyh4PWBGUFRTL0dgLCB5PWAyMCtgLCBsYWJlbD1mdWxsX25hbWUpKSArCiAgZ2VvbV9qaXR0ZXIoCiAgICBkYXRhPUFMTF9URV9GUDEwLCAKICAgIGdyb3VwT25YPVRSVUUsIAogICAgYWVzKHg9YEZQVFMvR2AsIHk9YDIwK2ApLCBjb2xvcj0icmVkIikgKwogIGxhYnMoeD0iRmFudGFzeSBQb2ludHMgUGVyIEdhbWUiLCB5PSJOdW1iZXIgb2YgMjArIFlhcmQgUmVjZXB0aW9ucyIsIHRpdGxlPSJDb3JyZWxhdGlvbiBCZXR3ZWVuIE51bWJlciBvZiAyMCBZYXJkIFJlY2VwdGlvbnMgYW5kIEZhbnRhc3kgUG9pbnRzIFBlciBHYW1lIGJ5IFRpZ2h0IEVuZHMiLCBzdWJ0aXRsZT0iKipEYXRhIHRocm91Z2ggV2VlayAxMSoqIikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCiNOb3RlCkl0IGFwcGVhcnMgdGhhdCBhIG1ham9yaXR5IG9mIHRoZSB0b3AgMTAgdGlnaHQgZW5kcyBhbHNvIGZhbGwgaW4gdGhlIHRvcCAxMCBvZiBudW1iZXIgb2YgMjArIHlhcmQgcmVjZXB0aW9ucy4gVGhpcyBmdXJ0aGVyIGNvbmZpcm1zIG15IGluaXRhbCB0aG91Z2h0LgoKYGBge3J9CmdncGxvdCgpICsgCiAgZ2VvbV9qaXR0ZXIoCiAgICBkYXRhPUFMTF9URV9GUCwgCiAgICBhZXMoeD1gRlBUUy9HYCwgeT1MRyksIGNvbG9yPSJncmV5IikgICsKICBnZW9tX3RleHRfcmVwZWwoCiAgICBkYXRhPUFMTF9URV9GUCwgCiAgICBhZXMoeD1gRlBUUy9HYCwgeT1MRywgbGFiZWw9ZnVsbF9uYW1lKSkgKwogIGdlb21faml0dGVyKAogICAgZGF0YT1BTExfVEVfRlAxMCwgCiAgICBncm91cE9uWD1UUlVFLCAKICAgIGFlcyh4PWBGUFRTL0dgLCB5PWBMR2ApLCBjb2xvcj0icmVkIikgKwogIGxhYnMoeD0iRmFudGFzeSBQb2ludHMgUGVyIEdhbWUiLCB5PSJMb25nZXN0IEdhaW4iLCB0aXRsZT0iQ29ycmVsYXRpb24gQmV0d2VlbiBMb25nZXN0IEdhaW4gdGhpcyBzZWFzb24gYW5kIEZhbnRhc3kgUG9pbnRzIFBlciBHYW1lIGJ5IFRpZ2h0IEVuZHMiLCBzdWJ0aXRsZT0iKipEYXRhIHRocm91Z2ggV2VlayAxMSoqIikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCmBgYHtyfQpnZ3Bsb3QoKSArIAogIGdlb21faml0dGVyKAogICAgZGF0YT1BTExfVEVfRlAsIAogICAgYWVzKHg9YEZQVFMvR2AsIHk9VEQpLCBjb2xvcj0iZ3JleSIpICArCiAgZ2VvbV90ZXh0X3JlcGVsKAogICAgZGF0YT1BTExfVEVfRlAsIAogICAgYWVzKHg9YEZQVFMvR2AsIHk9VEQsIGxhYmVsPWZ1bGxfbmFtZSkpICsKICBnZW9tX2ppdHRlcigKICAgIGRhdGE9QUxMX1RFX0ZQMTAsIAogICAgZ3JvdXBPblg9VFJVRSwgCiAgICBhZXMoeD1gRlBUUy9HYCwgeT1URCksIGNvbG9yPSJyZWQiKSArCiAgbGFicyh4PSJGYW50YXN5IFBvaW50cyBQZXIgR2FtZSIsIHk9IlRvdWNoZG93bnMiLCB0aXRsZT0iQ29ycmVsYXRpb24gQmV0d2VlbiBUb3VjaGRvd25zIGFuZCBGYW50YXN5IFBvaW50cyBQZXIgR2FtZSBieSBUaWdodCBFbmRzIiwgc3VidGl0bGU9IioqRGF0YSB0aHJvdWdoIFdlZWsgMTEqKiIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCiNOb3RlCkNsZWFybHksIHRoZXJlIGlzIGEgY29ycmVsYXRpb24gYmV0d2VlbiB0b3VjaGRvd25zIGFuZCBmYW50YXN5IHBvaW50cy4gSG93ZXZlciwgSSBmZWVsIHRoYXQgdGhpcyBpcyBub3QgdGhlIGJlc3QgaW5kaWNhdG9yIG9mIHN1Y2Nlc3MgYXQgdGhlIHRpZ2h0IGVuZCBwb3NpdGlvbiB0aG91Z2ggaXQgZmFjdG9ycy4KCiNDb25jbHVzaW9uClRpZ2h0IGVuZCBoYXMgYWx3YXlzIGJlZW4gYSB3aWxkIGNhcmQgaW4gZmFudGFzeSBmb290YmFsbCwgYm90aCBpbiB0aGUgZHJhZnRpbmcgcHJvY2VzcyBhbmQgdGhyb3VnaG91dCB0aGUgcmVndWxhciBzZWFzb24uIEhvd2V2ZXIsIHRoaXMgcmVhbGl0eSB3YXMgbWFnbmlmaWVkIGV2ZW4gbW9yZSBzbyBpbiAyMDIyIGFuZCBjaGFuZ2VzIHBlcnNwZWN0aXZlIG9uIGhvdyB0aGUgcG9zaXRpb24gc2hvdWxkIGJlIHZhbHVlZC4gV2hlbiBUcmF2aXMgS2VsY2Ugd2FzIHByb2plY3RlZCBpbiB0aGUgZmlyc3Qgcm91bmQgaW4gUFBSIGZvcm1hdHMsIHNvbWUgaW5jbHVkaW5nIG15c2VsZiBpbml0aWFsbHkgc2NvZmZlZC4gSG93ZXZlciwgYmFzZWQgb24gdGhlIHZvbGF0aWxpdHkgb2YgdGhlIHBvc2l0aW9uIGl0IGFwcGVhcnMgdGhhdCBndWFyYW50ZWVpbmcgZWxpdGUgcGVyZm9ybWFuY2UgZnJvbSBhIHNtYWxsIGdyb3VwIG9mIGVsaXRlIHRpZ2h0IGVuZHMgbWF5IGNoYW5nZSBkcmFmdGluZyBzdHJhdGVnaWVzIG1vdmluZyBmb3J3YXJkLgoKRnVydGhlcm1vcmUsIHdoZW4gZXZhbHVhdGluZyB0aWdodCBlbmRzIHNwZWNpZmljYWxseSwgaXQgYXBwZWFycyB0aGUgYmlnZ2VzdCBjb3JyZWxhdGlvbiB0byBmYW50YXN5IHN1Y2Nlc3MgaXMgZXhwbG9zaXZlIHBsYXlzLiBUaWdodCBlbmRzIHRlbmQgcmVjZWl2ZSBsZXNzIHZvbHVtZSB0aGFuIG90aGVyIHBhc3MgY2F0Y2hlcnMuIFRoZSBwbGF5ZXJzIHdobyBjYW4gbWF4aW1pemUgdGhlc2Ugb3Bwb3J0dW5pdGllcyBjbGVhcmx5IHRocml2ZSBhbmQgYXJlIHBsYXllcnMgeW91IHdhbnQgb24geW91ciB0ZWFtLiAKCkFub3RoZXIgdGhpbmcgdG8gbm90ZSBpcyBjb21wZXRpdGlvbiBmb3IgdGFyZ2V0cy4gVGhvdWdoIFlBQyBpcyBraW5nIGZvciB0aWdodCBlbmRzLCB2b2x1bWUgbmV2ZXIgaHVydHMuIFBsYXllcnMgbGlrZSBLZWxjZSwgQW5kcmV3cywgSG9ja2Vuc29uLCBhbmQgRXJ0eiBhcmUgYWxsIGVsaXRlIHRhbGVudHMgdGhhdCBwbGF5IGluIG9mZmVuc2VzIHdobyBhcmUgbGFja2luZyBlbGl0ZSBwbGF5bWtlcnMgb24gdGhlIG91dHNpZGUuIFRoaXMgaXMgaW50ZXJlc3RpbmcgYmVjYXVzZSB0aGVzZSBwbGF5ZXJzIGFyZSBhbHJlYWR5IGV4cGxvc2l2ZSBhbmQgYXJlIGdpdmVuIG1vcmUgY2hhbmNlcyB0byBiZSBleHBsb3NpdmUgZHVlIHRvIGxlc3NlciB0YWxlbnQgYXQgV1IuIAoKV2l0aCBhbGwgdGhpcyBiZWluZyBzYWlkLCBpdCB3b3VsZCBiZSB3aXNlIHRvIHRhcmdldCBhbiBlbGl0ZSBURSB0aGF0IGlzIGEgcHJpbWFyeSB3ZWFwb24gaW4gYSBnb29kIG9mZmVuc2UgYW5kIGlzIHN0cm9uZyBhZnRlciB0aGUgY2F0Y2guIEluIGZhY3QsIGJlY2F1c2Ugb2YgZGVwdGggYXQgb3RoZXIgcG9zaXRpb25zLCB0aGVyZSBpcyBhIGxlZ2l0aW1hdGUgY2FzZXMgdGhhdCBpdCBpcyBuZXZlciB0b28gZWFybHkgdG8gZHJhZnQgYW4gZWxpdGUgdGlnaHQgZW5kLiAKCiNSdW5uaW5nIEJhY2sKRmlyc3QsIEkgd2lsbCBhbmFseXplIHJ1bm5pbmcgc3BlY2lmaWMgY2F0ZWdvcmllcyBiZWZvcmUgc3BlY2lmaWNhbGx5IGZvY3VzaW5nIG9uIHBhc3NpbmcuIEZvciBydW5uaW5nIGJhY2tzLCB2b2x1bWUgYXBwZWFycyB0byBiZSB5b3VyIG1haW4gdGFyZ2V0LCBlc3BlY2lhbGx5IHdoZW4gYSBsYXJnZSB2b2x1bWUgY29tZXMgaW4gdGhlIHBhc3NpbmcgZ2FtZXMuIEhvd2V2ZXIsIGFsbCBncmVhdCBydW5uaW5nIGJhY2tzIGhhdmUgYSBzdGVhZHkgZmxvb3IgYXMgYSBydXNoZXIsIGVsZXZhdGluZyB0aGVpciBjZWlsaW5nIHdpdGggc3Ryb25nIHBhc3MgcHJvZHVjdGlvbi4gCgpgYGB7cn0KZ2dwbG90KCkgKyAKICBnZW9tX2ppdHRlcigKICAgIGRhdGE9QUxMX1JCX0ZQLCAKICAgIGFlcyh4PWBGUFRTL0dgLCB5PVRvdGFsUnVzaEF0dGVtcHRzKSwgY29sb3I9ImdyZXkiKSAgKwogIGdlb21fdGV4dF9yZXBlbCgKICAgIGRhdGE9QUxMX1JCX0ZQLCAKICAgIGFlcyh4PWBGUFRTL0dgLCB5PVRvdGFsUnVzaEF0dGVtcHRzLCBsYWJlbD1mdWxsX25hbWUpKSArCiAgZ2VvbV9qaXR0ZXIoCiAgICBkYXRhPUFMTF9SQl9GUDEwLCAKICAgIGdyb3VwT25YPVRSVUUsIAogICAgYWVzKHg9YEZQVFMvR2AsIHk9VG90YWxSdXNoQXR0ZW1wdHMpLCBjb2xvcj0icmVkIikgKwogIGxhYnMoeD0iRmFudGFzeSBQb2ludHMgUGVyIEdhbWUiLCB5PSJUb3RhbCBSdXNoIEF0dGVtcHRzIiwgdGl0bGU9IkNvcnJlbGF0aW9uIEJldHdlZW4gUnVzaCBBdHRlbXB0cyBhbmQgRmFudGFzeSBQb2ludHMgUGVyIEdhbWUgYnkgUnVubmluZyBCYWNrcyIsIHN1YnRpdGxlPSIqKkRhdGEgdGhyb3VnaCBXZWVrIDExKioiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAojTm90ZQpUaGlzIGNoYXJ0IHRlbGxzIHlvdSB0d28gbWFpbiB0aGluZ3MuIEZpcnN0LCBpdCBjbGFyaWZpZXMgdGhhdCBpbmRlZWQgdGhlcmUgaXMgYSBtYXNzaXZlIGNvcnJlbGF0aW9uIGJldHdlZW4gdm9sdW1lIGFuZCBmYW50YXN5IHN0cmljdGx5IGFzIGEgcnVubmVyLiBTZWNvbmRseSwgaXQgY2xhcmlmaWVzIHRoYXQgdGhlIGJlc3QgcnVubmluZyBiYWNrcyBhcmUgZG9taW5hbnQgaW4gdGhlaXIgY29tbWl0dGVlcy4gU3BsaXQgYmFja2ZpZWxkcyBhcmUgZGVhdGggaW4gZmFudGFzeSBmb290YmFsbCBzbyB5b3UgYXJlIGxvb2tpbmcgZm9yIGhpZ2ggdm9sdW1lIGFuZCBhIHN0cm9uZyBwZXJjZW50YWdlIG9mIGEgdGVhbSdzIHVhZ2UuCgpgYGB7cn0KZ2dwbG90KCkgKyAKICBnZW9tX2ppdHRlcigKICAgIGRhdGE9QUxMX1JCX0ZQLCAKICAgIGFlcyh4PWBGUFRTL0dgLCB5PVlQQyksIGNvbG9yPSJncmV5IikgICsKICBnZW9tX3RleHRfcmVwZWwoCiAgICBkYXRhPUFMTF9SQl9GUCwgCiAgICBhZXMoeD1gRlBUUy9HYCwgeT1ZUEMsIGxhYmVsPWZ1bGxfbmFtZSkpICsKICBnZW9tX2ppdHRlcigKICAgIGRhdGE9QUxMX1JCX0ZQMTAsIAogICAgZ3JvdXBPblg9VFJVRSwgCiAgICBhZXMoeD1gRlBUUy9HYCwgeT1ZUEMpLCBjb2xvcj0icmVkIikgKwogIGxhYnMoeD0iRmFudGFzeSBQb2ludHMgUGVyIEdhbWUiLCB5PSJZYXJkcyBQZXIgQ2FycnkiLCB0aXRsZT0iQ29ycmVsYXRpb24gQmV0d2VlbiBZYXJkcyBwZXIgQ2FycnkgYW5kIEZhbnRhc3kgUG9pbnRzIFBlciBHYW1lIGJ5IFJ1bm5pbmcgQmFja3MiLCBzdWJ0aXRsZT0iKipEYXRhIHRocm91Z2ggV2VlayAxMSoqIikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKI05vdGUKSW50ZXJlc3RpbmdseSB0aGVyZSBpcyBub3QgYSBzdHJvbmcgY29ycmVsYXRpb24gYmV0d2VlbiB5YXJkcyBwZXIgY2FycnkgYW5kIEZQUEcuIFRvbnkgUG9sbGFyZCBmb3IgZXhhbXBsZSwgaXMgZWxpdGUgaW4gdGVybXMgb2YgWVBDLCBob3dldmVyIHRoZSBDb3dib3lzIGFyZSBkZWFkc2V0IG9uIGZlZWRpbmcgWmVrZSB3aGljaCBwcmV2ZW50cyBQb2xsYXJkIGZyb20gYmVpbmcgZWxpdGUgZHVlIHRvIGEgbGFjayBvZiB2b2x1bWUuIFlvdSB3YW50IHRvIHRhcmdldCBoaWdoIFlQQyBydW5uZXJzIHdpdGggYSBzb2xpZCB2b2x1bWUgZmxvb3IuIAoKYGBge3J9CmdncGxvdCgpICsgCiAgZ2VvbV9qaXR0ZXIoCiAgICBkYXRhPUFMTF9SQl9GUCwgCiAgICBhZXMoeD1gRlBUUy9HYCwgeT1gMjArYCksIGNvbG9yPSJncmV5IikgICsKICBnZW9tX3RleHRfcmVwZWwoCiAgICBkYXRhPUFMTF9SQl9GUCwgCiAgICBhZXMoeD1gRlBUUy9HYCwgeT1gMjArYCwgbGFiZWw9ZnVsbF9uYW1lKSkgKwogIGdlb21faml0dGVyKAogICAgZGF0YT1BTExfUkJfRlAxMCwgCiAgICBncm91cE9uWD1UUlVFLCAKICAgIGFlcyh4PWBGUFRTL0dgLCB5PWAyMCtgKSwgY29sb3I9InJlZCIpICsKICBsYWJzKHg9IkZhbnRhc3kgUG9pbnRzIFBlciBHYW1lIiwgeT0iTnVtYmVyIG9mIDIwKyBZYXJkIFJ1bnMiLCB0aXRsZT0iQ29ycmVsYXRpb24gQmV0d2VlbiAyMCsgWWFyZCBSdW5zIGFuZCBGYW50YXN5IFBvaW50cyBQZXIgR2FtZSBieSBSdW5uaW5nIEJhY2tzIiwgc3VidGl0bGU9IioqRGF0YSB0aHJvdWdoIFdlZWsgMTEqKiIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgojTm90ZQpUaGlzIGdyYXBoIHBvaW50cyB0byBhIHRoZW1lIG9mIHZvbHVtZS4gVGhlIGJlc3QgcnVubmluZyBiYWNrcyBoYXZlIHRoZSBtb3N0IGV4cGxvc2l2ZSBydW5zIHdoaWNoIHNlZW1zIG9idmlvdXMuIEhvd2V2ZXIsIHRoaXMgaXMgYmVjYXVzZSB0aGVpciB0ZWFtcyB1bmRlcnN0YW5kIHRoZWlyIGhvbWUgcnVuIHBvdGVudGlhbCwgZ2l2aW5nIHRoZW0gYW1wbGUgb3Bwb3J0dW5pdGllcyB0byBicmVhayBhIGxvbmcgcnVuLiBUaGUgcGxheWVycyBvdXRzaWRlIHRoZSB0b3AgMTAgd2hvIGhhdmUgYSBsb3Qgb2YgYmlnIHJ1bnMgaGFkIHNwbGl0IGJhY2tmaWVsZHMgZm9yIGEgbWFqb3JpdHkgb2YgdGhlIHNlYXNvbiwgZ2l2aW5nIHRoZW0gbGVzcyBvcHB1cnV0bml0eSBkZXNwaXRlIHRoZWlyIG9idmlvdXMga25hY2sgZm9yIGl0LiAKClNvIG1hbnkgdGltZXMgd2UgaGF2ZSBzZWVuIGEgZ3JlYXQgcnVubmluZyBiYWNrIHN0cnVnZ2xlIGZvciBzdHJldGNoZXMgb2YgZ2FtZXMgYmVmb3JlIHB1bGxpbmcgYSA2MC15YXJkIHRvdWNoZG93biBydW4gb3V0IG9mIGhpcyBoYXQuIFRoZSBtb3JlIGNoYW5jZXMgeW91IGFyZSBnaXZlbiwgdGhlIG1vcmUgbGlrZWx5IHlvdSBhcmUgdG8gYnJlYWsgZnJlZSBhbmQgZ2FpbiBwb2ludHMuCgpgYGB7cn0KZ2dwbG90KCkgKyAKICBnZW9tX2ppdHRlcigKICAgIGRhdGE9QUxMX1JCX0ZQLCAKICAgIGFlcyh4PWBGUFRTL0dgLCB5PWBURC4uLjZgKSwgY29sb3I9ImdyZXkiKSAgKwogIGdlb21fdGV4dF9yZXBlbCgKICAgIGRhdGE9QUxMX1JCX0ZQLCAKICAgIGFlcyh4PWBGUFRTL0dgLCB5PWBURC4uLjZgLCBsYWJlbD1mdWxsX25hbWUpKSArCiAgZ2VvbV9qaXR0ZXIoCiAgICBkYXRhPUFMTF9SQl9GUDEwLCAKICAgIGdyb3VwT25YPVRSVUUsIAogICAgYWVzKHg9YEZQVFMvR2AsIHk9YFRELi4uNmApLCBjb2xvcj0icmVkIikgKwogIGxhYnMoeD0iRmFudGFzeSBQb2ludHMgUGVyIEdhbWUiLCB5PSJUb3VjaGRvd25zIiwgdGl0bGU9IkNvcnJlbGF0aW9uIEJldHdlZW4gVG91Y2hkb3ducyBhbmQgRmFudGFzeSBQb2ludHMgUGVyIEdhbWUgYnkgUnVubmluZyBCYWNrcyIsIHN1YnRpdGxlPSIqKkRhdGEgdGhyb3VnaCBXZWVrIDExKioiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAojTm90ZQpUb3VjaGRvd25zIGFyZSBhIGRpcmVjdCBjb3JyZWxhdGlvbiB0byBzdWNjZXNzIGFzIHdlbGwuIEphbWFhbCBXaWxsaWFtcyBwcm92ZXMgc29tZXRoaW5nIGludGVyZXN0aW5nIGhvd2V2ZXIgYXMgYSBsb3cgdm9sdW1lIHJ1bm5lciB3aXRoIHRoZSBsZWFkIGxlYWd1ZSBpbiB0b3VjaGRvd25zLiBUaGlzIGlzIGJlY2F1c2UgaGUgcmVjZWl2ZXMgYSBtYWpvcml0eSBvZiB0aGUgZ29hbC1saW5lIHdvcmsuIEdvYWwtbGluZSB2b2x1bWUgaXMgYSBjbGVhciBjb3JyZWxhdGlvbiB0byBmYW50YXN5IHBvaW50cywgY29udGludWluZyBhIHRyZW5kIGF0IHJ1bm5pbmcgYmFjay4KCmBgYHtyfQpnZ3Bsb3QoKSArIAogIGdlb21faml0dGVyKAogICAgZGF0YT1BTExfUkJfRlAsIAogICAgYWVzKHg9YEZQVFMvR2AsIHk9IFRHVCksIGNvbG9yPSJncmV5IikgICsKICBnZW9tX3RleHRfcmVwZWwoCiAgICBkYXRhPUFMTF9SQl9GUCwgCiAgICBhZXMoeD1gRlBUUy9HYCwgeT1UR1QsIGxhYmVsPWZ1bGxfbmFtZSkpICsKICBnZW9tX2ppdHRlcigKICAgIGRhdGE9QUxMX1JCX0ZQMTAsIAogICAgZ3JvdXBPblg9VFJVRSwgCiAgICBhZXMoeD1gRlBUUy9HYCwgeT1UR1QpLCBjb2xvcj0icmVkIikgKwogIGxhYnMoeD0iRmFudGFzeSBQb2ludHMgUGVyIEdhbWUiLCB5PSJUYXJnZXRzIiwgdGl0bGU9IkNvcnJlbGF0aW9uIEJldHdlZW4gVGFyZ2V0cyBhbmQgRmFudGFzeSBQb2ludHMgUGVyIEdhbWUgYnkgUnVubmluZyBCYWNrcyIsIHN1YnRpdGxlPSIqKkRhdGEgdGhyb3VnaCBXZWVrIDExKioiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAojTm90ZQpJbnRlcmVzdGluZ2x5LCBpdCBzZWVtcyB0aGF0IHRhcmdldHMgYXJlIGxlc3MgY29ycmVsYXRlZCB0byBmYW50YXN5IHN1Y2Nlc3MgdW5sZXNzIHlvdSBhcmUgQXVzdGluIEVja2VsZXIgb3IgQ01DLCByZWNlaXZpbmcgYSBtYXNzaXZlIHBhc3Npbmcgdm9sdW1lLiBIb3dldmVyLCBhIG1ham9yaXR5IG9mIHRoZSB0b3AgcnVubmluZyBiYWNrcyBoYXBwZW4gdG8gZmFsbCBpbiB0aGUgdXBwZXIgcmVnaW9ucyBvZiB0YXJnZXRzLiAgCgpgYGB7cn0KZ2dwbG90KCkgKyAKICBnZW9tX2ppdHRlcigKICAgIGRhdGE9QUxMX1JCX0ZQLCAKICAgIGFlcyh4PWBGUFRTL0dgLCB5PVJFQyksIGNvbG9yPSJncmV5IikgICsKICBnZW9tX3RleHRfcmVwZWwoCiAgICBkYXRhPUFMTF9SQl9GUCwgCiAgICBhZXMoeD1gRlBUUy9HYCwgeT1SRUMsIGxhYmVsPWZ1bGxfbmFtZSkpICsKICBnZW9tX2ppdHRlcigKICAgIGRhdGE9QUxMX1JCX0ZQMTAsIAogICAgZ3JvdXBPblg9VFJVRSwgCiAgICBhZXMoeD1gRlBUUy9HYCwgeT1SRUMpLCBjb2xvcj0icmVkIikgKwogIGxhYnMoeD0iRmFudGFzeSBQb2ludHMgUGVyIEdhbWUiLCB5PSJSZWNlcHRpb25zIiwgdGl0bGU9IkNvcnJlbGF0aW9uIEJldHdlZW4gUmVjZXB0aW9ucyBhbmQgRmFudGFzeSBQb2ludHMgUGVyIEdhbWUgYnkgUnVubmluZyBCYWNrcyIsIHN1YnRpdGxlPSIqKkRhdGEgdGhyb3VnaCBXZWVrIDExKioiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAojTm90ZQpNb3JlIHRhcmdldHMgbWVhbiBtb3JlIHJlY2VwdGlvbnMuIFZPTFVNRSEgVk9MVU1FISBWT0xVTUUhCgpgYGB7cn0KZ2dwbG90KCkgKyAKICBnZW9tX2ppdHRlcigKICAgIGRhdGE9QUxMX1JCX0ZQLCAKICAgIGFlcyh4PWBGUFRTL0dgLCB5PWBZL1JgKSwgY29sb3I9ImdyZXkiKSAgKwogIGdlb21fdGV4dF9yZXBlbCgKICAgIGRhdGE9QUxMX1JCX0ZQLCAKICAgIGFlcyh4PWBGUFRTL0dgLCB5PWBZL1JgLCBsYWJlbD1mdWxsX25hbWUpKSArCiAgZ2VvbV9qaXR0ZXIoCiAgICBkYXRhPUFMTF9SQl9GUDEwLCAKICAgIGdyb3VwT25YPVRSVUUsIAogICAgYWVzKHg9YEZQVFMvR2AsIHk9YFkvUmApLCBjb2xvcj0icmVkIikgKwogIGxhYnMoeD0iRmFudGFzeSBQb2ludHMgUGVyIEdhbWUiLCB5PSJZYXJkcyBwZXIgUmVjZXB0aW9uIiwgdGl0bGU9IkNvcnJlbGF0aW9uIEJldHdlZW4gWWFyZHMgcGVyIFJlY2VwdGlvbiBhbmQgRmFudGFzeSBQb2ludHMgUGVyIEdhbWUgYnkgUnVubmluZyBCYWNrcyIsIHN1YnRpdGxlPSIqKkRhdGEgdGhyb3VnaCBXZWVrIDExKioiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAojTm90ZQpZYXJkcyBwZXIgcmVjZXB0aW9uIGlzIGNsZWFybHkgYSB2YWd1ZSBzdGF0LCBhZ2FpbiBsaWtlbHkgaGF2aW5nIHRvIGJlIGNvcnJlbGF0ZWQgdG8gdm9sdW1lLiAKCmBgYHtyfQpnZ3Bsb3QoKSArIAogIGdlb21faml0dGVyKAogICAgZGF0YT1BTExfUkJfRlAsIAogICAgYWVzKHg9YEZQVFMvR2AsIHk9YFRELi4uMTFgKSwgY29sb3I9ImdyZXkiKSAgKwogIGdlb21fdGV4dF9yZXBlbCgKICAgIGRhdGE9QUxMX1JCX0ZQLCAKICAgIGFlcyh4PWBGUFRTL0dgLCB5PWBURC4uLjExYCwgbGFiZWw9ZnVsbF9uYW1lKSkgKwogIGdlb21faml0dGVyKAogICAgZGF0YT1BTExfUkJfRlAxMCwgCiAgICBncm91cE9uWD1UUlVFLCAKICAgIGFlcyh4PWBGUFRTL0dgLCB5PWBURC4uLjExYCksIGNvbG9yPSJyZWQiKSArCiAgbGFicyh4PSJGYW50YXN5IFBvaW50cyBQZXIgR2FtZSIsIHk9IlJlY2VpdmluZyBUb3VjaGRvd25zIiwgdGl0bGU9IkNvcnJlbGF0aW9uIEJldHdlZW4gUmVjZWl2aW5nIFRvdWNoZG93bnMgYW5kIEZhbnRhc3kgUG9pbnRzIFBlciBHYW1lIGJ5IFJ1bm5pbmcgQmFja3MiLCBzdWJ0aXRsZT0iKipEYXRhIHRocm91Z2ggV2VlayAxMSoqIikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCiNOb3RlCk5vdCBtdWNoIGNvcnJlbGF0aW9uIGJldHdlZW4gcmVjZWl2aW5nIHRvdWNoZG93bnMgYW5kIEZQUEcuCgojQ29uY2x1c2lvbgpPdmVyYWxsLCBteSBpbml0aWFsIGh5cG90aGVzaXMgd2FzIHJpZ2h0LiBWb2x1bWUgaXMgYWJzb2x1dGVseSBrZXkuCgotIFRhcmdldCBydW5uaW5nIGJhY2tzIHdpdGggbGltaXRlZCBjb21wZXRpdGlvbiBpbiB0aGVpciBiYWNrZmllbGQuIFRoaXMgcmVzdWx0cyBpbiBhIG1vcmUgcnVzaCBhdHRlbXB0cywgbW9yZSB0YXJnZXRzLCBhbmQgbW9yZSBvcHB1cnVuaXRpZXMgdG8gbWFrZSBiaWcgcGxheXMuIAoKLVJ1bm5pbmcgYmFja3Mgd2hvIHJlY2VpdmUgZWxpdGUgdXNnYWUgYW5kIHByZXR0eSBnb29kIHBhc3Npbmcgdm9sdW1lIGFyZSBlbGl0ZSBydW5uaW5nIGJhY2tzLgoKLVBhc3Npbmcgdm9sdW1lIGFsb25lIGlzIG5vdCBldmVuIGNsb3NlIHRvIGVub3VnaCB0byBtYWludGFpbiBmYW50YXN5IHJlbGV2YW5jZS4gCgotIEF2b2lkIHBsYXllcnMgaW4gc3BsaXQgYmFja2ZpZWxkcywgZXNwZWNhaWxseSB3aGVuIHRoZWlyIHJvbGUgaXMgbWFpbmx5IGFzIGEgcGFzcyBjYXRjaGVyLgoKLSBHb2FsaW5lIHVzYWdlIGlzIG1hc3NpdmUgZm9yIHJ1bm5pbmcgYmFja3MgYXMgVEQncyBjb3JyZWxhdGUgZGlyZWN0bHkgdG8gaW5jcmVhc2VkIGZhbnRhc3kgcG9pbnRzLgoKI1JlY2VpdmVycwpJIGtub3cgdGhhdCB2b2x1bWUgaXMgaW1wb3J0YW50IGZvciBXUnMgYXMgd2VsbCwgaG93ZXZlciBJIHdhbnQgdG8gZGV0ZXJtaW5lIHdoaWNoIHR5cGUgb2Ygdm9sdW1lIGlzIGJlc3QuCgpgYGB7cn0KZ2dwbG90KCkgKyAKICBnZW9tX2ppdHRlcigKICAgIGRhdGE9QUxMX1dSX0ZQLCAKICAgIGFlcyh4PWBGUFRTL0dgLCB5PVRvdGFsX0FpcllhcmRzKSwgY29sb3I9ImdyZXkiKSAgKwogIGdlb21fdGV4dF9yZXBlbCgKICAgIGRhdGE9QUxMX1dSX0ZQLCAKICAgIGFlcyh4PWBGUFRTL0dgLCB5PVRvdGFsX0FpcllhcmRzLCBsYWJlbD1mdWxsX25hbWUpKSArCiAgZ2VvbV9qaXR0ZXIoCiAgICBkYXRhPUFMTF9XUl9GUDEwLCAKICAgIGdyb3VwT25YPVRSVUUsIAogICAgYWVzKHg9YEZQVFMvR2AsIHk9VG90YWxfQWlyWWFyZHMpLCBjb2xvcj0icmVkIikgKwogIGxhYnMoeD0iRmFudGFzeSBQb2ludHMgUGVyIEdhbWUiLCB5PSJUb3RhbCBBaXIgWWFyZHMiLCB0aXRsZT0iQ29ycmVsYXRpb24gQmV0d2VlbiBUb3RhbCBBaXIgWWFyZHMgYW5kIEZhbnRhc3kgUG9pbnRzIFBlciBHYW1lIGJ5IFdpZGUgUmVjZWl2ZXJzIiwgc3VidGl0bGU9IioqRGF0YSB0aHJvdWdoIFdlZWsgMTEqKiIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgojTm90ZQpUb3RhbCBhaXIgeWFyZHMgaXMgcmVwcmVzZW50YXRpdmUgb2YgZWl0aGVyIGZld2VyIGJ1dCBsb25nZXIgdGFyZ2V0cyBvciBhIGxvdCBvZiBwYXNzZXMgdGhyb3duIGEgcGxheWVycyB3YXkgaW4gZ2VuZXJhbC4gSXQgbWFrZXMgYSBsb3Qgb2Ygc2Vuc2UgdGhhdCBzb21lIG9mIHRoZSBiZXN0IHJlY2VpdmVycyBoYXZlIHRoZSBtb3N0IHRvdGFsIGFpciB5YXJkcy4gVGhlIGVsaXRlIHJlY2VpdmVycyBvbiB0aGlzIGxpc3Qgbm90IGluIHRoZSB0b3AgcGVyY2VudGFnZSBvZiBhaXIgeWFyZHMgaGF2ZSBtaXNzZWQgYSBzaWduaWZpY2FudCBjaHVuayBvZiBnYW1lcywgcHJvdmluZyB0aGF0IGFpciB5YXJkcyBhcmUgdml0YWwuIAoKYGBge3J9CmdncGxvdCgpICsgCiAgZ2VvbV9qaXR0ZXIoCiAgICBkYXRhPUFMTF9XUl9GUCwgCiAgICBhZXMoeD1gRlBUUy9HYCwgeT1BdmdfQWlyWWFyZHMpLCBjb2xvcj0iZ3JleSIpICArCiAgZ2VvbV90ZXh0X3JlcGVsKAogICAgZGF0YT1BTExfV1JfRlAsIAogICAgYWVzKHg9YEZQVFMvR2AsIHk9QXZnX0FpcllhcmRzLCBsYWJlbD1mdWxsX25hbWUpKSArCiAgZ2VvbV9qaXR0ZXIoCiAgICBkYXRhPUFMTF9XUl9GUDEwLCAKICAgIGdyb3VwT25YPVRSVUUsIAogICAgYWVzKHg9YEZQVFMvR2AsIHk9QXZnX0FpcllhcmRzKSwgY29sb3I9InJlZCIpICsKICBsYWJzKHg9IkZhbnRhc3kgUG9pbnRzIFBlciBHYW1lIiwgeT0iQXZlcmFnZSBBaXIgWWFyZHMiLCB0aXRsZT0iQ29ycmVsYXRpb24gQmV0d2VlbiBBdmVyYWdlIEFpciBZYXJkcyBhbmQgRmFudGFzeSBQb2ludHMgUGVyIEdhbWUgYnkgV2lkZSBSZWNlaXZlcnMiLCBzdWJ0aXRsZT0iKipEYXRhIHRocm91Z2ggV2VlayAxMSoqIikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKI05vdGUKVGhpcyBncmFwaCBpcyBzaW1pbGFyIHRvIGRlcHRoIG9mIHRhcmdldC4gV2hpbGUgdGhlIGJlc3QgcmVjZWl2ZXJzIGFyZSBwcmV0dHkgaGlnaCB1cCB0aGVyZSBpbiBhdmVyYWdlIGFpciB5YXJkcywgbm9uZSBhcHBlYXIgdG8gYmUgZWxpdGUgaW4gdGhlIGNhdGVnb3J5IGFzIHRoZWlyIHZvbHVtZSBzdXBlcnNlZWRzIGl0LgoKYGBge3J9CmdncGxvdCgpICsgCiAgZ2VvbV9qaXR0ZXIoCiAgICBkYXRhPUFMTF9XUl9GUCwgCiAgICBhZXMoeD1gRlBUUy9HYCwgeT1BdmdfX1lBQyksIGNvbG9yPSJncmV5IikgICsKICBnZW9tX3RleHRfcmVwZWwoCiAgICBkYXRhPUFMTF9XUl9GUCwgCiAgICBhZXMoeD1gRlBUUy9HYCwgeT1BdmdfX1lBQywgbGFiZWw9ZnVsbF9uYW1lKSkgKwogIGdlb21faml0dGVyKAogICAgZGF0YT1BTExfV1JfRlAxMCwgCiAgICBncm91cE9uWD1UUlVFLCAKICAgIGFlcyh4PWBGUFRTL0dgLCB5PUF2Z19fWUFDKSwgY29sb3I9InJlZCIpICsKICBsYWJzKHg9IkZhbnRhc3kgUG9pbnRzIFBlciBHYW1lIiwgeT0iQXZlcmFnZSBZYXJkcyBwZXIgQ2F0Y2giLCB0aXRsZT0iQ29ycmVsYXRpb24gQmV0d2VlbiBBdmVyYWdlIFlhcmRzIHBlciBDYXRjaCBhbmQgRmFudGFzeSBQb2ludHMgUGVyIEdhbWUgYnkgV2lkZSBSZWNlaXZlcnMiLCBzdWJ0aXRsZT0iKipEYXRhIHRocm91Z2ggV2VlayAxMSoqIikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCiNOb3RlCkl0IHNlZW1zIHRoYXQgWVBDIGlzIGEgbW9yZSByYW5kb20gc3RhdGlzaXRjIGluIGRldGVybWluZSBmYW50YXN5IHN1Y2Nlc3MgYXQgV1IuCgpgYGB7cn0KZ2dwbG90KCkgKyAKICBnZW9tX2ppdHRlcigKICAgIGRhdGE9QUxMX1dSX0ZQLCAKICAgIGFlcyh4PWBGUFRTL0dgLCB5PUF2Z19SZWNlaXZpbmdZZHMpLCBjb2xvcj0iZ3JleSIpICArCiAgZ2VvbV90ZXh0X3JlcGVsKAogICAgZGF0YT1BTExfV1JfRlAsIAogICAgYWVzKHg9YEZQVFMvR2AsIHk9QXZnX1JlY2VpdmluZ1lkcywgbGFiZWw9ZnVsbF9uYW1lKSkgKwogIGdlb21faml0dGVyKAogICAgZGF0YT1BTExfV1JfRlAxMCwgCiAgICBncm91cE9uWD1UUlVFLCAKICAgIGFlcyh4PWBGUFRTL0dgLCB5PUF2Z19SZWNlaXZpbmdZZHMpLCBjb2xvcj0icmVkIikgKwogIGxhYnMoeD0iRmFudGFzeSBQb2ludHMgUGVyIEdhbWUiLCB5PSJBdmVyYWdlIFJlY2VpdmluZyBZYXJkcyIsIHRpdGxlPSJDb3JyZWxhdGlvbiBCZXR3ZWVuIEF2ZXJhZ2UgUmVjZWl2aW5nIFlhcmRzIGFuZCBGYW50YXN5IFBvaW50cyBQZXIgR2FtZSBieSBXaWRlIFJlY2VpdmVycyIsIHN1YnRpdGxlPSIqKkRhdGEgdGhyb3VnaCBXZWVrIDExKioiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKI05vdGUKQWdhaW4gbGVzcyBvZiBhIGNvcnJlbGF0aW9uLiAKCmBgYHtyfQpnZ3Bsb3QoKSArIAogIGdlb21faml0dGVyKAogICAgZGF0YT1BTExfV1JfRlAsIAogICAgYWVzKHg9YEZQVFMvR2AsIHk9VG90YWxSZWNlaXZpbmdZZHMpLCBjb2xvcj0iZ3JleSIpICArCiAgZ2VvbV90ZXh0X3JlcGVsKAogICAgZGF0YT1BTExfV1JfRlAsIAogICAgYWVzKHg9YEZQVFMvR2AsIHk9VG90YWxSZWNlaXZpbmdZZHMsIGxhYmVsPWZ1bGxfbmFtZSkpICsKICBnZW9tX2ppdHRlcigKICAgIGRhdGE9QUxMX1dSX0ZQMTAsIAogICAgZ3JvdXBPblg9VFJVRSwgCiAgICBhZXMoeD1gRlBUUy9HYCwgeT1Ub3RhbFJlY2VpdmluZ1lkcyksIGNvbG9yPSJyZWQiKSArCiAgbGFicyh4PSJGYW50YXN5IFBvaW50cyBQZXIgR2FtZSIsIHk9IlRvdGFsIFJlY2VpdmluZyBZYXJkcyIsIHRpdGxlPSJDb3JyZWxhdGlvbiBCZXR3ZWVuIFRvdGFsIFJlY2VpdmluZyBZYXJkcyBhbmQgRmFudGFzeSBQb2ludHMgUGVyIEdhbWUgYnkgV2lkZSBSZWNlaXZlcnMiLCBzdWJ0aXRsZT0iKipEYXRhIHRocm91Z2ggV2VlayAxMSoqIikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKI0NvbmNsdXNpb24KT3ZlcmFsbCwgZXZlbiBtb3JlIHNvIHRoYW4gcnVubmluZyBiYWNrcywgdm9sdW1lIGlzIGtleSBhdCByZWNlaXZlci4gWW91IHdhbnQgdG8gdGFyZ2V0IHJlY2VpdmVycyBpbiBvZmZlbnNlcyB3aG8gdGhyb3cgdGhlIGJhbGwgYSBsb3QsIGhhdmUgYSBnb29kIHF1YXJ0ZXJiYWNrIGFuZCBhcmUgaGVhdmlseSBmZWF0dXJlZCBpbiB0aGVpciBvZmZlbnNlLiBJbiBmYWN0LCBtb3N0IG9mIHRoZSBlbGl0ZSByZWNlaXZlcnMgaGF2ZSBvZmZlbnNlcyBidWlsdCBhcm91bmQgZWl0aGVyIHRoZWlyIHRhbGVudCBvciB0aGVpciBxdWFydGVyYmFja3MgdGFsZW50LiBDaGFzZSBlbGl0ZSBwbGF5ZXJzIGluIGEgY2xlYXIgYW5kIGRlZmluZWQgcm9sZS4gCgojT3ZlcmFsbCBDb25jbHVzaW9ucwpXaGlsZSBmYW50YXN5IGlzIGEgbWFqb3JpdHkgbHVjaywgdW5kZXJzdGFuZGluZyB0aGVzZSBjb25jZXB0cyB3aWxsIGFsbG93IGZhbnRhc3kgcGxheWVycyB0byBmb2N1cyBvbiBzcGVjaWZpYyBtYXJrZXJzIHRvIGNvbnNpZGVyIHdoZW4gZHJhZnRpbmcsIG1ha2luZyB0cmFkZXMsIGRldGVybWluaW5nIHdobyB0byBzdGFydCBvciB3aG8gdG8gZ3JhYiBvZmYgdGhlIHdhaXZlcnMuIEhvd2V2ZXIsIGZvciB0aGlzIGZpbmFsIGFuYWx5c2lzLCBJIHdpbGwgbWFpbmx5IGZvY3VzIG9uIGRyYWZ0aW5nIHB1cnBvc2VzLgoKI0RyYWZ0aW5nIFFCcwpJZiB5b3UgYXJlIGdvaW5nIHRvIGRyYWZ0IGEgcXVhcnRlcmJhY2sgZWFybHkgaW4gdGhlIGRyYWZ0LCB0aGV5IGJldHRlciBiZSBuYW1lZCBQYXRyaWNrIE1haG9tZXMgb3Igb2ZmZXIgZWl0aGVyIGVsaXRlIHBhc3Npbmcgd2l0aCBhIGRlY2VudCBydW5uaW5nIGZsb29yIG9yIGFuIGVsaXRlIHJ1bm5pbmcgcXVhcnRlcmJhY2suCgojRHJhZnRpbmcgUnVubmluZyBCYWNrcwotQ2hhc2Ugdm9sdW1lIGFzIGEgcnVubmVyCi1UYXJnZXQgcGxheWVycyB3aG8gYXJlIGNsZWFybHkgdGhlIG1haW4gZ3V5IGFuZCB3aWxsIHJlY2VpdmUgYSBtYWpvcml0eSBvZiB0aGUgcnVubmluZyBiYWNrIHNuYXBzLgotIEluIDIwMjIsIHJ1bm5pbmcgYmFja3Mgd2VyZSBhIGRpbWUgYSBkb3plbi4gTWFrZSBzdXJlIGlmIHlvdSBkcmFmdCBhIHJ1bm5pbmcgYmFjayBlYXJseSwgeW91IGFyZSBidXlpbmcgaW50byBhIHBsYXllciB3aG8geW91IGtub3cgaXMgd29ydGh5IG9mIHRoZSB2b2x1bWUuCi0gSWYgYSBydW5uaW5nIGJhY2sgaXMga25vd24gZm9yIGhpcyB1dGlsaXphdGlvbiBpbiB0aGUgcGFzc2luZyBnYW1lIGFuZCBpcyBwcm9qZWN0ZWQgZm9yIGEgYmlnZ2VyIHJvbGUgYXMgYSBydW5uZXIsIHRoZXkgY291bGQgYmUgYSBzbGVlcGVyLgotWW91IG5lZWQgcnVubmluZyBiYWNrcyB3aG8gcmVjZWl2ZSBnb2FsLWxpbmUgd29yay4gVm9sdW1lIGFuZCB5YXJkcyBhbG9uZSBhcmUgbm90IGVub3VnaCBmb3Igc3VzdGFpbmFiaWxpdHkuCi1Bdm9pZCBhbnl0aGluZyBsZXNzIHRoYW4gYSA2MC80MCBzcGxpdCBvZiBjYXJyaWVzLgoKI0RyYWZ0aW5nIFRpZ2h0IEVuZHMKLUlmIHRoZXJlIGlzIGFuIGVsaXRlIGd1eSB0aGVyZSwgZ28gZ2V0IGhpbS4gSSBrbm93IHRoYXQgb25seSByZWZlcnMgdG8gYWJvdXQgZm91ciBwbGF5ZXJzLCBidXQgdGhpcyBqdXN0IHNob3dzIGhvdyBsYXJnZSB0aGUgZHJvcC1vZmYgaXMuCi0gVGFraW5nIEtlbGNlIGF0IGFueSBwb2ludCBpbiB0aGUgZmlyc3Qgcm91bmQgaXMgdW5kZXJzdGFuZGFibGUgYW5kIG1heWJlIGV2ZW4gd2lzZSBtb3ZpbmcgZm9yd2FyZC4gLSBUYXJnZXQgZXhwbG9zaXZlIHBsYXllcnMgd2hvIGFyZSB0YXJnZXRlZCBkb3duIHRoZSBmaWVsZCBvZnRlbiBhbmQgdGhyaXZlIG9uIFlBQy4KCiNEcmFmdGluZyBXUnMKLSBBdCB0aGUgdG9wIG9mIHRoZSBkcmFmdCwgYWltIGZvciBlbGl0ZSB0YWxlbnRzLCBpbiBlbGl0ZSBvZmZlbnNlcyB3aXRoIGdvb2QgcXVhcnRlcmJhY2tzLCBkb24ndCBvdmVyIHRoaW5rIGl0Lgo=